diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts index 303528f11..170994408 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts @@ -1,7 +1,10 @@ import { insertEdgelessTextCommand } from '@blocksuite/affine-block-edgeless-text'; +import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame'; import { CanvasElementType, EdgelessCRUDIdentifier, + getSurfaceBlock, + getSurfaceComponent, } from '@blocksuite/affine-block-surface'; import { FontFamilyIcon } from '@blocksuite/affine-components/icons'; import { @@ -37,7 +40,11 @@ import { captureEventTarget, matchModels, } from '@blocksuite/affine-shared/utils'; -import { type BlockStdScope, stdContext } from '@blocksuite/block-std'; +import { + type BlockComponent, + type BlockStdScope, + stdContext, +} from '@blocksuite/block-std'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import type { XYWH } from '@blocksuite/global/gfx'; import { @@ -58,7 +65,6 @@ import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; import * as Y from 'yjs'; -import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js'; import { type AUTO_COMPLETE_TARGET_TYPE, AutoCompleteFrameOverlay, @@ -125,7 +131,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { constructor( position: [number, number], - edgeless: EdgelessRootBlockComponent, + edgeless: BlockComponent, currentSource: ShapeElementModel | NoteBlockModel, connector: ConnectorElementModel ) { @@ -140,6 +146,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { return this.std.get(EdgelessCRUDIdentifier); } + get surface() { + return getSurfaceComponent(this.std); + } + private _addFrame() { const bound = this._generateTarget(this.connector)?.nextBound; if (!bound) return; @@ -152,9 +162,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { const { xywh, position } = target; const edgeless = this.edgeless; - const { service, surfaceBlockModel } = edgeless; - const frameMgr = service.frame; - const frameIndex = service.frames.length + 1; + const surfaceBlockModel = getSurfaceBlock(this.std.store); + if (!surfaceBlockModel) return; + const frameMgr = this.std.get(EdgelessFrameManagerIdentifier); + const frameIndex = frameMgr.frames.length + 1; const props = this.std.get(EditPropsStore).applyLastProps('affine:frame', { title: new Y.Text(`Frame ${frameIndex}`), xywh: serializeXYWH(...xywh), @@ -170,7 +181,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { position, }; - edgeless.service.selection.set({ + this.gfx.selection.set({ elements: [frame.id], editing: false, }); @@ -209,7 +220,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { this.crud.updateElement(this.connector.id, { target: { id, position }, }); - this.edgeless.service.selection.set({ + this.gfx.selection.set({ elements: [id], editing: false, }); @@ -395,7 +406,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { } private _getPanelPosition() { - const { viewport } = this.edgeless.service; + const { viewport } = this.gfx; const { boundingClientRect: viewportRect, zoom } = viewport; const result = this._getTargetXYWH(PANEL_WIDTH / zoom, PANEL_HEIGHT / zoom); const pos = result ? result.xywh.slice(0, 2) : this.position; @@ -442,11 +453,14 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { } private _removeOverlay() { - if (this._overlay) - this.edgeless.surface.renderer.removeOverlay(this._overlay); + if (this._overlay && this.surface) { + this.surface.renderer.removeOverlay(this._overlay); + } } private _showFrameOverlay() { + if (!this.surface) return; + const bound = this._generateTarget(this.connector)?.nextBound; if (!bound) return; @@ -459,7 +473,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { .get(ThemeProvider) .getCssVariableColor('--affine-black-30'); this._overlay = new AutoCompleteFrameOverlay(this.gfx, xywh, strokeColor); - this.edgeless.surface.renderer.addOverlay(this._overlay); + this.surface.renderer.addOverlay(this._overlay); } private _showNoteOverlay() { @@ -468,6 +482,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { DEFAULT_NOTE_OVERLAY_HEIGHT )?.xywh; if (!xywh) return; + if (!this.surface) return; const background = this.edgeless.std .get(ThemeProvider) @@ -478,12 +493,13 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { true ); this._overlay = new AutoCompleteNoteOverlay(this.gfx, xywh, background); - this.edgeless.surface.renderer.addOverlay(this._overlay); + this.surface.renderer.addOverlay(this._overlay); } private _showOverlay(targetType: AUTO_COMPLETE_TARGET_TYPE) { this._removeOverlay(); if (!this._connectorExist()) return; + if (!this.surface) return; switch (targetType) { case 'text': @@ -499,12 +515,13 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { this._showShapeOverlay(targetType); } - this.edgeless.surface.refresh(); + this.surface.refresh(); } private _showShapeOverlay(targetType: TARGET_SHAPE_TYPE) { const bound = this._generateTarget(this.connector)?.nextBound; if (!bound) return; + if (!this.surface) return; const { x, y, w, h } = bound; const xywh = [x, y, w, h] as XYWH; @@ -537,7 +554,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { shapeStyle ); - this.edgeless.surface.renderer.addOverlay(this._overlay); + this.surface.renderer.addOverlay(this._overlay); } private _showTextOverlay() { @@ -546,9 +563,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { DEFAULT_TEXT_HEIGHT )?.xywh; if (!xywh) return; + if (!this.surface) return; this._overlay = new AutoCompleteTextOverlay(this.gfx, xywh); - this.edgeless.surface.renderer.addOverlay(this._overlay); + this.surface.renderer.addOverlay(this._overlay); } override connectedCallback() { @@ -568,9 +586,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { override firstUpdated() { this.disposables.add( - this.edgeless.service.viewport.viewportUpdated.subscribe(() => - this.requestUpdate() - ) + this.gfx.viewport.viewportUpdated.subscribe(() => this.requestUpdate()) ); } @@ -650,7 +666,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { accessor currentSource: ShapeElementModel | NoteBlockModel; @property({ attribute: false }) - accessor edgeless: EdgelessRootBlockComponent; + accessor edgeless: BlockComponent; @property({ attribute: false }) accessor position: [number, number]; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts index e7c280a1f..cd19c77b0 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts @@ -3,6 +3,8 @@ import { type ConnectionOverlay, ConnectorPathGenerator, EdgelessCRUDIdentifier, + getSurfaceBlock, + getSurfaceComponent, isNoteBlock, Overlay, OverlayIdentifier, @@ -24,7 +26,11 @@ import { shapeMethods, } from '@blocksuite/affine-model'; import { handleNativeRangeAtPoint } from '@blocksuite/affine-shared/utils'; -import { type BlockStdScope, stdContext } from '@blocksuite/block-std'; +import { + type BlockComponent, + type BlockStdScope, + stdContext, +} from '@blocksuite/block-std'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { DisposableGroup } from '@blocksuite/global/disposable'; import type { Bound, IVec } from '@blocksuite/global/gfx'; @@ -42,7 +48,6 @@ import { property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; -import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js'; import type { SelectedRect } from '../rects/edgeless-selected-rect.js'; import { EdgelessAutoCompletePanel } from './auto-complete-panel.js'; import { @@ -158,6 +163,10 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } `; + private get _surface() { + return getSurfaceBlock(this.std.store); + } + private _autoCompleteOverlay!: AutoCompleteOverlay; private readonly _onPointerDown = (e: PointerEvent, type: Direction) => { @@ -167,7 +176,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { e.clientY - viewportRect.top ); - if (!this.edgeless.dispatcher) return; + if (!this.edgeless.std.event) return; let connector: ConnectorElementModel | null; @@ -207,7 +216,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { if (!this._isMoving) { this._generateElementOnClick(type); } else if (connector && !connector.target.id) { - this.edgeless.service.selection.clear(); + this.gfx.selection.clear(); this._createAutoCompletePanel(e, connector); } @@ -343,10 +352,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { ) { if (!this.canShowAutoComplete) return; - const position = this.edgeless.service.viewport.toModelCoord( - e.clientX, - e.clientY - ); + const position = this.gfx.viewport.toModelCoord(e.clientX, e.clientY); const autoCompletePanel = new EdgelessAutoCompletePanel( position, this.edgeless, @@ -358,7 +364,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } private _generateElementOnClick(type: Direction) { - const { doc, service } = this.edgeless; + const { doc } = this.edgeless; const bound = this._computeNextBound(type); const id = createEdgelessElement(this.edgeless, this.current, bound); if (!id) return; @@ -384,7 +390,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { if (!model) { return; } - const [x, y] = service.viewport.toViewCoord( + const [x, y] = this.gfx.viewport.toViewCoord( bound.center[0], bound.y + DEFAULT_NOTE_HEIGHT / 2 ); @@ -393,7 +399,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { }); } - this.edgeless.service.selection.set({ + this.gfx.selection.set({ elements: [id], editing: true, }); @@ -401,9 +407,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } private _getConnectedElements(element: ShapeElementModel) { - const service = this.edgeless.service; + if (!this._surface) return []; - return service.getConnectors(element.id).reduce((prev, current) => { + return this._surface.getConnectors(element.id).reduce((prev, current) => { if (current.target.id === element.id && current.source.id) { prev.push( this.crud.getElementById(current.source.id) as ShapeElementModel @@ -469,7 +475,8 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } private _initOverlay() { - const { surface } = this.edgeless; + const surface = getSurfaceComponent(this.std); + if (!surface) return; this._autoCompleteOverlay = new AutoCompleteOverlay(this.gfx); surface.renderer.addOverlay(this._autoCompleteOverlay); } @@ -477,7 +484,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { private _renderArrow() { const isShape = this.current instanceof ShapeElementModel; const { selectedRect } = this; - const { zoom } = this.edgeless.service.viewport; + const { zoom } = this.gfx.viewport; const width = 72; const height = 44; @@ -572,7 +579,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } const { selectedRect } = this; - const { zoom } = this.edgeless.service.viewport; + const { zoom } = this.gfx.viewport; const size = 26; const buttonMargin = (mindmapButtons.mindmapNode?.children.length ?? 0) > 0 @@ -644,7 +651,8 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { path: IVec[], targetType: ShapeType ) { - const { surface } = this.edgeless; + const surface = getSurfaceComponent(this.std); + if (!surface) return; this._autoCompleteOverlay.stroke = surface.renderer.getColorValue( current.strokeColor, @@ -667,7 +675,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { } override firstUpdated() { - const { _disposables, edgeless } = this; + const { _disposables, edgeless, gfx } = this; _disposables.add( this.gfx.selection.slots.updated.subscribe(() => { @@ -681,8 +689,8 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { _disposables.add( edgeless.host.event.add('pointerMove', ctx => { const evt = ctx.get('pointerState'); - const [x, y] = edgeless.gfx.viewport.toModelCoord(evt.x, evt.y); - const elm = edgeless.gfx.getElementByPoint(x, y); + const [x, y] = gfx.viewport.toModelCoord(evt.x, evt.y); + const elm = gfx.getElementByPoint(x, y); if (!elm) { this._isHover = false; @@ -703,7 +711,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { removeOverlay() { this._timer && clearTimeout(this._timer); - this.edgeless.surface.renderer.removeOverlay(this._autoCompleteOverlay); + const surface = getSurfaceComponent(this.std); + if (!surface) return; + surface.renderer.removeOverlay(this._autoCompleteOverlay); } override render() { @@ -740,7 +750,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { accessor current!: ShapeElementModel | NoteBlockModel; @property({ attribute: false }) - accessor edgeless!: EdgelessRootBlockComponent; + accessor edgeless!: BlockComponent; @property({ attribute: false }) accessor selectedRect!: SelectedRect; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/utils.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/utils.ts index 62fc7c209..3e2de8977 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/utils.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/auto-complete/utils.ts @@ -1,4 +1,5 @@ import { + EdgelessCRUDIdentifier, type Options, Overlay, type RoughCanvas, @@ -14,14 +15,13 @@ import { type ShapeName, type ShapeStyle, } from '@blocksuite/affine-model'; +import type { BlockComponent } from '@blocksuite/block-std'; import type { GfxController, GfxModel } from '@blocksuite/block-std/gfx'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { Bound, normalizeDegAngle, type XYWH } from '@blocksuite/global/gfx'; import { assertType } from '@blocksuite/global/utils'; import * as Y from 'yjs'; -import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js'; - export enum Direction { Right, Bottom, @@ -270,14 +270,13 @@ export function capitalizeFirstLetter(str: string) { } export function createEdgelessElement( - edgeless: EdgelessRootBlockComponent, + edgeless: BlockComponent, current: ShapeElementModel | NoteBlockModel, bound: Bound ) { - let id; - const { service } = edgeless; - const { crud } = service; + const crud = edgeless.std.get(EdgelessCRUDIdentifier); + let id; let element: GfxModel | null = null; if (isShape(current)) { @@ -331,11 +330,11 @@ export function createEdgelessElement( } export function createShapeElement( - edgeless: EdgelessRootBlockComponent, + edgeless: BlockComponent, current: ShapeElementModel | NoteBlockModel, targetType: TARGET_SHAPE_TYPE ) { - const { crud } = edgeless.service; + const crud = edgeless.std.get(EdgelessCRUDIdentifier); const id = crud.addElement('shape', { shapeType: getShapeType(targetType), radius: getShapeRadius(targetType),