fix(editor): suface component can be null (#12270)

Closes: BS-3149

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

## Summary by CodeRabbit

- **Refactor**
  - Improved internal handling of surface components across various tools, resulting in safer and more consistent access patterns.
  - Enhanced code maintainability and reliability without altering any visible features or user workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Saul-Mirone
2025-05-14 08:37:10 +00:00
parent 7e722957a9
commit f2164e4d70
6 changed files with 39 additions and 34 deletions

View File

@@ -34,6 +34,10 @@ export class EraserTool extends BaseTool {
private readonly _eraseTargets = new Set<GfxModel>(); private readonly _eraseTargets = new Set<GfxModel>();
private get _surfaceComponent() {
return this.gfx.surfaceComponent as SurfaceBlockComponent | null;
}
private readonly _loop = () => { private readonly _loop = () => {
const now = Date.now(); const now = Date.now();
const elapsed = now - this._timestamp; const elapsed = now - this._timestamp;
@@ -59,7 +63,7 @@ export class EraserTool extends BaseTool {
}) })
); );
this._overlay.d = d; this._overlay.d = d;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.refresh(); this._surfaceComponent?.refresh();
} }
this._timer = requestAnimationFrame(this._loop); this._timer = requestAnimationFrame(this._loop);
}; };
@@ -81,9 +85,7 @@ export class EraserTool extends BaseTool {
return; return;
} }
( this._surfaceComponent?.renderer.removeOverlay(this._overlay);
this.gfx.surfaceComponent as SurfaceBlockComponent
)?.renderer.removeOverlay(this._overlay);
this._erasable.clear(); this._erasable.clear();
this._eraseTargets.clear(); this._eraseTargets.clear();
} }
@@ -150,8 +152,7 @@ export class EraserTool extends BaseTool {
...this.gfx.layer.blocks, ...this.gfx.layer.blocks,
]); ]);
this._loop(); this._loop();
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.renderer.addOverlay(
this._overlay this._surfaceComponent?.renderer.addOverlay(this._overlay);
);
} }
} }

View File

@@ -312,7 +312,8 @@ export class MindMapDragExtension extends InteractivityExtension {
mindmapNode: MindmapNode, mindmapNode: MindmapNode,
pos: { x: number; y: number } pos: { x: number; y: number }
) { ) {
const surfaceBlock = this.gfx.surfaceComponent as SurfaceBlockComponent; const surfaceBlock = this.gfx
.surfaceComponent as SurfaceBlockComponent | null;
const renderer = surfaceBlock?.renderer; const renderer = surfaceBlock?.renderer;
const indicatorOverlay = this._indicatorOverlay; const indicatorOverlay = this._indicatorOverlay;

View File

@@ -47,20 +47,22 @@ export class NoteTool extends BaseTool<NoteToolOption> {
private _noteOverlay: NoteOverlay | null = null; private _noteOverlay: NoteOverlay | null = null;
private get _surfaceComponent() {
return this.gfx.surfaceComponent as SurfaceBlockComponent | null;
}
// Ensure clear overlay before adding a new note // Ensure clear overlay before adding a new note
private _clearOverlay() { private _clearOverlay() {
this._noteOverlay = this._disposeOverlay(this._noteOverlay); this._noteOverlay = this._disposeOverlay(this._noteOverlay);
this._draggingNoteOverlay = this._disposeOverlay(this._draggingNoteOverlay); this._draggingNoteOverlay = this._disposeOverlay(this._draggingNoteOverlay);
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); this._surfaceComponent?.refresh();
} }
private _disposeOverlay(overlay: NoteOverlay | null) { private _disposeOverlay(overlay: NoteOverlay | null) {
if (!overlay) return null; if (!overlay) return null;
overlay.dispose(); overlay.dispose();
( this._surfaceComponent?.renderer.removeOverlay(overlay);
this.gfx.surfaceComponent as SurfaceBlockComponent
)?.renderer.removeOverlay(overlay);
return null; return null;
} }
@@ -69,7 +71,7 @@ export class NoteTool extends BaseTool<NoteToolOption> {
if (!this._noteOverlay) return; if (!this._noteOverlay) return;
this._noteOverlay.globalAlpha = 0; this._noteOverlay.globalAlpha = 0;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.refresh(); this._surfaceComponent?.refresh();
} }
private _resize(shift = false) { private _resize(shift = false) {
@@ -102,7 +104,7 @@ export class NoteTool extends BaseTool<NoteToolOption> {
if (!this._noteOverlay) return; if (!this._noteOverlay) return;
this._noteOverlay.x = x; this._noteOverlay.x = x;
this._noteOverlay.y = y; this._noteOverlay.y = y;
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); this._surfaceComponent?.refresh();
} }
override activate() { override activate() {
@@ -111,9 +113,7 @@ export class NoteTool extends BaseTool<NoteToolOption> {
const background = attributes.background; const background = attributes.background;
this._noteOverlay = new NoteOverlay(this.gfx, background); this._noteOverlay = new NoteOverlay(this.gfx, background);
this._noteOverlay.text = this.activatedOption.tip; this._noteOverlay.text = this.activatedOption.tip;
(this.gfx.surfaceComponent as SurfaceBlockComponent).renderer.addOverlay( this._surfaceComponent?.renderer.addOverlay(this._noteOverlay);
this._noteOverlay
);
} }
override click(e: PointerEventState): void { override click(e: PointerEventState): void {
@@ -176,9 +176,7 @@ export class NoteTool extends BaseTool<NoteToolOption> {
this.std.get(EditPropsStore).lastProps$.value['affine:note']; this.std.get(EditPropsStore).lastProps$.value['affine:note'];
const background = attributes.background; const background = attributes.background;
this._draggingNoteOverlay = new DraggingNoteOverlay(this.gfx, background); this._draggingNoteOverlay = new DraggingNoteOverlay(this.gfx, background);
(this.gfx.surfaceComponent as SurfaceBlockComponent).renderer.addOverlay( this._surfaceComponent?.renderer.addOverlay(this._draggingNoteOverlay);
this._draggingNoteOverlay
);
} }
override mounted() { override mounted() {

View File

@@ -1,5 +1,5 @@
import { import {
type SurfaceBlockComponent, getSurfaceComponent,
ToolOverlay, ToolOverlay,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { type Color, DefaultTheme } from '@blocksuite/affine-model'; import { type Color, DefaultTheme } from '@blocksuite/affine-model';
@@ -36,7 +36,8 @@ export class NoteOverlay extends ToolOverlay {
if (this.gfx.tool.currentToolName$.value !== 'affine:note') return; if (this.gfx.tool.currentToolName$.value !== 'affine:note') return;
const tool = this.gfx.tool.currentTool$.peek() as NoteTool; const tool = this.gfx.tool.currentTool$.peek() as NoteTool;
this.text = this._getOverlayText(tool.activatedOption.tip); this.text = this._getOverlayText(tool.activatedOption.tip);
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); const surface = getSurfaceComponent(this.gfx.std);
surface?.refresh();
}) })
); );
} }
@@ -139,7 +140,8 @@ export class DraggingNoteOverlay extends NoteOverlay {
this.disposables.add( this.disposables.add(
this.slots.draggingNoteUpdated.subscribe(({ xywh }) => { this.slots.draggingNoteUpdated.subscribe(({ xywh }) => {
[this.x, this.y, this.width, this.height] = xywh; [this.x, this.y, this.width, this.height] = xywh;
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); const surface = getSurfaceComponent(this.gfx.std);
surface?.refresh();
}) })
); );
} }

View File

@@ -1,7 +1,7 @@
import { import {
getSurfaceComponent,
type Options, type Options,
type RoughCanvas, type RoughCanvas,
type SurfaceBlockComponent,
ToolOverlay, ToolOverlay,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { import {
@@ -87,7 +87,8 @@ export class ShapeOverlay extends ToolOverlay {
shapeStyle shapeStyle
); );
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); const surface = getSurfaceComponent(this.gfx.std);
surface?.refresh();
}) })
); );
} }

View File

@@ -41,6 +41,10 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
// shape overlay // shape overlay
private _shapeOverlay: ShapeOverlay | null = null; private _shapeOverlay: ShapeOverlay | null = null;
private get _surfaceComponent() {
return this.gfx.surfaceComponent as SurfaceBlockComponent | null;
}
private _spacePressedCtx: { private _spacePressedCtx: {
draggingArea: IBound & { draggingArea: IBound & {
endX: number; endX: number;
@@ -91,7 +95,7 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
private _hideOverlay() { private _hideOverlay() {
if (!this._shapeOverlay) return; if (!this._shapeOverlay) return;
this._shapeOverlay.globalAlpha = 0; this._shapeOverlay.globalAlpha = 0;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.refresh(); this._surfaceComponent?.refresh();
} }
private _resize(shiftPressed = false, spacePressed = false) { private _resize(shiftPressed = false, spacePressed = false) {
@@ -152,7 +156,7 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
if (!this._shapeOverlay) return; if (!this._shapeOverlay) return;
this._shapeOverlay.x = x; this._shapeOverlay.x = x;
this._shapeOverlay.y = y; this._shapeOverlay.y = y;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.refresh(); this._surfaceComponent?.refresh();
} }
override activate() { override activate() {
@@ -163,11 +167,11 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
if (!this._shapeOverlay) return; if (!this._shapeOverlay) return;
this._shapeOverlay.dispose(); this._shapeOverlay.dispose();
(
this.gfx.surfaceComponent as SurfaceBlockComponent this._surfaceComponent?.renderer.removeOverlay(this._shapeOverlay);
)?.renderer.removeOverlay(this._shapeOverlay);
this._shapeOverlay = null; this._shapeOverlay = null;
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.renderer.refresh();
this._surfaceComponent?.renderer.refresh();
} }
override click(e: PointerEventState): void { override click(e: PointerEventState): void {
@@ -223,9 +227,7 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
fillColor: attributes.fillColor, fillColor: attributes.fillColor,
strokeColor: attributes.strokeColor, strokeColor: attributes.strokeColor,
}); });
(this.gfx.surfaceComponent as SurfaceBlockComponent)?.renderer.addOverlay( this._surfaceComponent?.renderer.addOverlay(this._shapeOverlay);
this._shapeOverlay
);
} }
override deactivate() { override deactivate() {