fix(editor): fix overlay of tool is not shown or repeated when switching tool (#11575)

Close [BS-3029](https://linear.app/affine-design/issue/BS-3029/frame-里面的-shape-没办法进入文本编辑模式)
Close [BS-3082](https://linear.app/affine-design/issue/BS-3082/按s切换至shape工具,在白板上点击会创建两个shape)
Close [BS-3091](https://linear.app/affine-design/issue/BS-3082/按s切换至shape工具,在白板上点击会创建两个shape)

## Fix Shape Tool Issues

This PR addresses several issues with the shape and mindmap tools functionality in the editor:

1. **Fix text editing after mode switching**: Resolves an issue where users couldn't edit text in shapes after switching editor modes. The fix ensures the edgeless block is properly retrieved when double-clicking on a shape.

2. **Improve tool switching behavior**: Fixes issues with tool overlays not showing or being repeated when switching between tools. This includes:
   - Properly handling tool overlay visibility
   - Ensuring only one tool is active at a time when using keyboard shortcuts
   - Adding proper cleanup when switching tools

3. **Add comprehensive tests**: Adds new test cases to verify:
   - Shape creation with keyboard shortcuts
   - Shape text editing after mode switching
   - Tool switching behavior with keyboard shortcuts
This commit is contained in:
L-Sun
2025-04-10 13:39:22 +00:00
parent 588659ef67
commit 823bf40a57
11 changed files with 142 additions and 68 deletions

View File

@@ -236,30 +236,39 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
const locked = this.gfx.viewport.locked;
const selection = this.gfx.selection;
if (locked || selection.editing) return;
if (this.readyToDrop) {
const activeIndex = shapes.findIndex(
s => s.name === this.draggingShape
);
const nextIndex = (activeIndex + 1) % shapes.length;
const next = shapes[nextIndex];
this.draggingShape = next.name;
this.draggableController.cancelWithoutAnimation();
}
const el = this.shapeContainer.querySelector(
`.shape.${this.draggingShape}`
) as HTMLElement;
if (!el) {
console.error('Edgeless toolbar Shape element not found');
if (
this.gfx.tool.dragging$.peek() &&
this.gfx.tool.currentToolName$.peek() === 'shape'
) {
return;
}
const { x, y } = this.gfx.tool.lastMousePos$.peek();
const { viewport } = this.edgeless.std.get(ViewportElementProvider);
const { left, top } = viewport;
const clientPos = { x: x + left, y: y + top };
this.draggableController.dragAndMoveTo(el, clientPos);
const activeIndex = shapes.findIndex(
s => s.name === this.draggingShape
);
const nextIndex = (activeIndex + 1) % shapes.length;
const next = shapes[nextIndex];
this.draggingShape = next.name;
if (this.readyToDrop) {
this.draggableController.cancelWithoutAnimation();
const el = this.shapeContainer.querySelector(
`.shape.${this.draggingShape}`
) as HTMLElement;
if (!el) {
console.error('Edgeless toolbar Shape element not found');
return;
}
const { x, y } = this.gfx.tool.lastMousePos$.peek();
const { viewport } = this.edgeless.std.get(ViewportElementProvider);
const { left, top } = viewport;
const clientPos = { x: x + left, y: y + top };
this.draggableController.dragAndMoveTo(el, clientPos);
} else {
this.setEdgelessTool('shape', {
shapeName: this.draggingShape,
});
}
},
},
{ global: true }

View File

@@ -89,7 +89,6 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
private _hideOverlay() {
if (!this._shapeOverlay) return;
this._shapeOverlay.globalAlpha = 0;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.refresh();
}

View File

@@ -13,9 +13,9 @@ export class ShapeElementView extends GfxElementModelView<ShapeElementModel> {
}
private _initDblClickToEdit(): void {
const edgeless = this.std.view.getBlock(this.std.store.root!.id);
this.on('dblclick', () => {
const edgeless = this.std.view.getBlock(this.std.store.root!.id);
if (edgeless && !this.model.isLocked()) {
mountShapeTextEditor(this.model, edgeless);
}