fix(editor): can not select the block after undo the drag from canvas to note (#12473)

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## 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.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
L-Sun
2025-05-23 07:28:30 +00:00
parent 41781902f6
commit 0902b2b9c9
4 changed files with 43 additions and 19 deletions
@@ -710,6 +710,7 @@ export class DragEventWatcher {
dropPayload: DropPayload, dropPayload: DropPayload,
point: Point point: Point
) => { ) => {
this.std.store.captureSync();
if (this.mode === 'edgeless') { if (this.mode === 'edgeless') {
this._onEdgelessDrop(dropBlock, dragPayload, dropPayload, point); this._onEdgelessDrop(dropBlock, dragPayload, dropPayload, point);
} else { } else {
@@ -200,7 +200,6 @@ export class GfxController extends LifeCycleWatcher {
...options, ...options,
all: true, all: true,
}); });
let picked = last(results) ?? null; let picked = last(results) ?? null;
const { activeGroup } = selectionManager; const { activeGroup } = selectionManager;
const first = picked; const first = picked;
+16 -18
View File
@@ -397,22 +397,14 @@ export class GridManager extends GfxExtension {
if (payload.type === 'add' && canBeRenderedAsGfxBlock(payload.model)) { if (payload.type === 'add' && canBeRenderedAsGfxBlock(payload.model)) {
this.add(payload.model); this.add(payload.model);
} }
if (payload.type === 'update') { if (payload.type === 'update') {
const model = store.getBlock(payload.id) const model = store.getModelById(payload.id);
?.model as GfxBlockElementModel; if (!model) return;
if (!model) {
return;
}
if (payload.props.key === 'xywh' && canBeRenderedAsGfxBlock(model)) { if (payload.props.key === 'xywh' && canBeRenderedAsGfxBlock(model)) {
this.update( this.update(model);
store.getBlock(payload.id)?.model as GfxBlockElementModel
);
} }
} }
if ( if (
payload.type === 'delete' && payload.type === 'delete' &&
payload.model instanceof GfxBlockElementModel payload.model instanceof GfxBlockElementModel
@@ -429,22 +421,28 @@ export class GridManager extends GfxExtension {
}); });
const watchSurface = (surface: SurfaceBlockModel) => { const watchSurface = (surface: SurfaceBlockModel) => {
let lastChildMap = new Map(surface.childMap.peek()); let lastChildMap = new Map<string, number>(surface.childMap.peek());
disposables.add( disposables.add(
surface.childMap.subscribe(val => { surface.childMap.subscribe(currentChildMap => {
val.forEach((_, id) => { currentChildMap.forEach((_, id) => {
if (lastChildMap.has(id)) { if (lastChildMap.has(id)) {
lastChildMap.delete(id); lastChildMap.delete(id);
return; return;
} }
}); });
lastChildMap.forEach((_, id) => { lastChildMap.forEach((_, id) => {
const block = store.getBlock(id); const model = store.getModelById(id);
if (block?.model) { if (model) {
this.remove(block.model as GfxBlockElementModel); 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);
}) })
); );
@@ -11,6 +11,7 @@ import {
addBasicRectShapeElement, addBasicRectShapeElement,
click, click,
clickInCenter, clickInCenter,
clickView,
dragBetweenCoords, dragBetweenCoords,
enterPlaygroundRoom, enterPlaygroundRoom,
getBoundingRect, getBoundingRect,
@@ -18,6 +19,7 @@ import {
initThreeParagraphs, initThreeParagraphs,
pressEnter, pressEnter,
pressEscape, pressEscape,
undoByKeyboard,
waitNextFrame, waitNextFrame,
} from '../../utils/actions/index.js'; } from '../../utils/actions/index.js';
import { import {
@@ -517,3 +519,27 @@ test('should the selected rect be below the edgeless element toolbar', async ({
expect(topElement).toBe('EDGELESS-TOOLBAR-WIDGET'); 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);
});