diff --git a/blocksuite/affine/block-database/src/detail-panel/block-renderer.ts b/blocksuite/affine/block-database/src/detail-panel/block-renderer.ts index 7fa55c5c62..f6dc118f6a 100644 --- a/blocksuite/affine/block-database/src/detail-panel/block-renderer.ts +++ b/blocksuite/affine/block-database/src/detail-panel/block-renderer.ts @@ -76,10 +76,6 @@ export class BlockRenderer return this.host?.doc.getBlock(this.rowId)?.model; } - get service() { - return this.host.std.getService('affine:database'); - } - override connectedCallback() { super.connectedCallback(); if (this.model && this.model.text) { diff --git a/blocksuite/affine/block-database/src/properties/title/text.ts b/blocksuite/affine/block-database/src/properties/title/text.ts index 3266264921..b780562609 100644 --- a/blocksuite/affine/block-database/src/properties/title/text.ts +++ b/blocksuite/affine/block-database/src/properties/title/text.ts @@ -123,10 +123,6 @@ abstract class BaseTextCell extends BaseCellRenderer { return this.host?.std.get(DefaultInlineManagerExtension.identifier); } - get service() { - return this.host?.std.getService('affine:database'); - } - get topContenteditableElement() { const databaseBlock = this.closest('affine-database'); diff --git a/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts b/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts index 268d6c747b..eb335ec624 100644 --- a/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts +++ b/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts @@ -40,10 +40,6 @@ export function toEdgelessEmbedBlock< return Bound.deserialize(this.model.xywh); } - get rootService() { - return this.std.getService('affine:page'); - } - _handleClick(_: MouseEvent): void { return; } diff --git a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts index 96ed8743a6..a859006e46 100644 --- a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts @@ -36,12 +36,6 @@ export class EmbedEdgelessLinkedDocBlockComponent extends toEdgelessEmbedBlock( bound.w = EMBED_CARD_WIDTH[style]; bound.h = EMBED_CARD_HEIGHT[style]; - const edgelessService = this.rootService; - - if (!edgelessService) { - return; - } - const { addBlock } = this.std.get(EdgelessCRUDIdentifier); const surface = this.gfx.surface ?? undefined; const newId = addBlock( @@ -67,10 +61,6 @@ export class EmbedEdgelessLinkedDocBlockComponent extends toEdgelessEmbedBlock( doc.deleteBlock(this.model); }; - get rootService() { - return this.std.getService('affine:page'); - } - protected override _handleClick(evt: MouseEvent): void { if (isNewTabTrigger(evt)) { this.open({ openMode: 'open-in-new-tab', event: evt }); diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts index a58d5d8b4a..36080351fa 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts @@ -123,16 +123,11 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock( override convertToCard = (aliasInfo?: AliasInfo) => { const { id, doc, caption, xywh } = this.model; - const edgelessService = this.rootService; const style = 'vertical'; const bound = Bound.deserialize(xywh); bound.w = EMBED_CARD_WIDTH[style]; bound.h = EMBED_CARD_HEIGHT[style]; - if (!edgelessService) { - return; - } - const { addBlock } = this.std.get(EdgelessCRUDIdentifier); const surface = this.gfx.surface ?? undefined; const newId = addBlock( @@ -159,10 +154,6 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock( doc.deleteBlock(this.model); }; - get rootService() { - return this.std.getService('affine:page'); - } - override renderGfxBlock() { const { style, xywh } = this.model; const bound = Bound.deserialize(xywh); diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts index 40455b81f2..0b34670241 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts @@ -351,10 +351,6 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent = (ctx, next) => { const { oldId, newId } = ctx; - const service = ctx.std.getService('affine:surface'); + const service = ctx.std.get(SurfaceBlockService); if (!oldId || !newId || !service) { next(); return; diff --git a/blocksuite/affine/block-surface/src/extensions/crud-extension.ts b/blocksuite/affine/block-surface/src/extensions/crud-extension.ts index 2b8fb7edd3..16ddfb3409 100644 --- a/blocksuite/affine/block-surface/src/extensions/crud-extension.ts +++ b/blocksuite/affine/block-surface/src/extensions/crud-extension.ts @@ -2,8 +2,10 @@ import type { SurfaceElementModelMap } from '@blocksuite/affine-model'; import { EditPropsStore } from '@blocksuite/affine-shared/services'; import { type BlockStdScope, StdIdentifier } from '@blocksuite/block-std'; import { + GfxBlockElementModel, GfxControllerIdentifier, type GfxModel, + isGfxGroupCompatibleModel, } from '@blocksuite/block-std/gfx'; import { type Container, createIdentifier } from '@blocksuite/global/di'; import { type BlockModel, Extension } from '@blocksuite/store'; @@ -155,4 +157,25 @@ export class EdgelessCRUDExtension extends Extension { } return this._surface.getElementsByType(type); } + + removeElement(id: string | GfxModel) { + id = typeof id === 'string' ? id : id.id; + + const el = this.getElementById(id); + if (isGfxGroupCompatibleModel(el)) { + el.childIds.forEach(childId => { + this.removeElement(childId); + }); + } + + if (el instanceof GfxBlockElementModel) { + this.std.store.deleteBlock(el); + return; + } + + if (this._surface?.hasElementById(id)) { + this._surface.deleteElement(id); + return; + } + } } diff --git a/blocksuite/affine/block-surface/src/surface-block.ts b/blocksuite/affine/block-surface/src/surface-block.ts index e05e25efd7..d68662c445 100644 --- a/blocksuite/affine/block-surface/src/surface-block.ts +++ b/blocksuite/affine/block-surface/src/surface-block.ts @@ -13,7 +13,10 @@ import { query } from 'lit/decorators.js'; import { ConnectorElementModel } from './element-model/index.js'; import { CanvasRenderer } from './renderer/canvas-renderer.js'; -import type { ElementRenderer } from './renderer/elements/index.js'; +import { + type ElementRenderer, + elementRenderers, +} from './renderer/elements/index.js'; import { OverlayIdentifier } from './renderer/overlay.js'; import type { SurfaceBlockModel } from './surface-model.js'; import type { SurfaceBlockService } from './surface-service.js'; @@ -126,10 +129,6 @@ export class SurfaceBlockComponent extends BlockComponent< this._renderer?.refresh(); }; - private get _edgelessService() { - return this.std.getService('affine:page') as unknown as SurfaceContext; - } - private get _gfx() { return this.std.get(GfxControllerIdentifier); } @@ -179,12 +178,12 @@ export class SurfaceBlockComponent extends BlockComponent< property, themeService.edgelessTheme ), - selectedElements: () => this._edgelessService.selection.selectedIds, + selectedElements: () => gfx.selection.selectedIds, }, onStackingCanvasCreated(canvas) { canvas.className = 'indexable-canvas'; }, - elementRenderers: this._edgelessService.elementRenderers, + elementRenderers, surfaceModel: this.model, }); @@ -205,7 +204,7 @@ export class SurfaceBlockComponent extends BlockComponent< }) ); this._disposables.add( - this._edgelessService.selection.slots.updated.on(() => { + gfx.selection.slots.updated.on(() => { this._renderer.refresh(); }) ); diff --git a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts b/blocksuite/blocks/src/_specs/preset/mobile-patch.ts index ae06814210..042440c8d5 100644 --- a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts +++ b/blocksuite/blocks/src/_specs/preset/mobile-patch.ts @@ -1,4 +1,5 @@ import type { CodeBlockConfig } from '@blocksuite/affine-block-code'; +import { ParagraphBlockService } from '@blocksuite/affine-block-paragraph'; import { type ReferenceNodeConfig, ReferenceNodeConfigIdentifier, @@ -100,7 +101,7 @@ export class MobileSpecsPatches extends LifeCycleWatcher { override mounted() { // remove slash placeholder for mobile: `type / ...` { - const paragraphService = this.std.getService('affine:paragraph'); + const paragraphService = this.std.get(ParagraphBlockService); if (!paragraphService) return; paragraphService.placeholderGenerator = model => { diff --git a/blocksuite/blocks/src/root-block/edgeless/components/frame/frame-preview.ts b/blocksuite/blocks/src/root-block/edgeless/components/frame/frame-preview.ts index bae27bbdc6..43b4ac469e 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/frame/frame-preview.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/frame/frame-preview.ts @@ -5,6 +5,7 @@ import { type EditorHost, ShadowlessElement, } from '@blocksuite/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { Bound, debounce, @@ -19,7 +20,6 @@ import { styleMap } from 'lit/directives/style-map.js'; import { SpecProvider } from '../../../../_specs/index.js'; import type { EdgelessRootPreviewBlockComponent } from '../../edgeless-root-preview-block.js'; -import type { EdgelessRootService } from '../../edgeless-root-service.js'; const DEFAULT_PREVIEW_CONTAINER_WIDTH = 280; const DEFAULT_PREVIEW_CONTAINER_HEIGHT = 166; @@ -144,12 +144,9 @@ export class FramePreview extends WithDisposable(ShadowlessElement) { if (!previewEditorHost) return; - const edgelessService = previewEditorHost.std.getService( - 'affine:page' - ) as EdgelessRootService; - + const { viewport } = previewEditorHost.std.get(GfxControllerIdentifier); const frameBound = Bound.deserialize(this.frame.xywh); - edgelessService.viewport.setViewportByBound(frameBound); + viewport.setViewportByBound(frameBound); } private _renderSurfaceContent() { diff --git a/blocksuite/blocks/src/root-block/widgets/ai-panel/ai-panel.ts b/blocksuite/blocks/src/root-block/widgets/ai-panel/ai-panel.ts index 257ace28ad..f42a63ba46 100644 --- a/blocksuite/blocks/src/root-block/widgets/ai-panel/ai-panel.ts +++ b/blocksuite/blocks/src/root-block/widgets/ai-panel/ai-panel.ts @@ -1,5 +1,6 @@ import type { AIError } from '@blocksuite/affine-components/ai-item'; import { + DocModeProvider, NotificationProvider, ThemeProvider, } from '@blocksuite/affine-shared/services'; @@ -8,6 +9,7 @@ import { stopPropagation, } from '@blocksuite/affine-shared/utils'; import { WidgetComponent } from '@blocksuite/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { assertExists } from '@blocksuite/global/utils'; import type { BaseSelection } from '@blocksuite/store'; import { @@ -24,8 +26,6 @@ import { css, html, nothing, type PropertyValues } from 'lit'; import { property, query } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; -import type { EdgelessRootService } from '../../edgeless/edgeless-root-service.js'; -import { PageRootService } from '../../page/page-root-service.js'; import { AFFINE_FORMAT_BAR_WIDGET } from '../format-bar/format-bar.js'; import { AFFINE_VIEWPORT_OVERLAY_WIDGET, @@ -363,12 +363,13 @@ export class AffineAIPanelWidget extends WidgetComponent { ): Partial { let rootBoundary: Rect | undefined; { - const rootService = this.host.std.getService('affine:page'); - if (rootService instanceof PageRootService) { + const docModeProvider = this.host.std.get(DocModeProvider); + if (docModeProvider.getEditorMode() === 'page') { rootBoundary = undefined; } else { + const gfx = this.host.std.get(GfxControllerIdentifier); // TODO circular dependency: instanceof EdgelessRootService - const viewport = (rootService as EdgelessRootService).viewport; + const viewport = gfx.viewport; rootBoundary = { x: viewport.left, y: viewport.top, diff --git a/blocksuite/playground/apps/_common/components/starter-debug-menu.ts b/blocksuite/playground/apps/_common/components/starter-debug-menu.ts index 8484c65b14..0c1e9c7cf7 100644 --- a/blocksuite/playground/apps/_common/components/starter-debug-menu.ts +++ b/blocksuite/playground/apps/_common/components/starter-debug-menu.ts @@ -19,6 +19,7 @@ import './left-side-panel.js'; import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { ColorScheme, ColorVariables, @@ -28,7 +29,6 @@ import { type DocMode, DocModeProvider, download, - EdgelessRootService, ExportManager, FontFamilyVariables, HtmlAdapterFactoryIdentifier, @@ -210,10 +210,6 @@ export class StarterDebugMenu extends ShadowlessElement { this.editor.mode = value; } - get rootService() { - return this.editor.std?.getService('affine:page'); - } - private _addNote() { const rootModel = this.doc.root; if (!rootModel) return; @@ -544,18 +540,8 @@ export class StarterDebugMenu extends ShadowlessElement { private _present() { if (!this.editor.std || !this.editor.host) return; - const rootService = this.editor.std.getService('affine:page'); - if (!(rootService instanceof EdgelessRootService)) { - toast( - this.editor.host, - 'The presentation mode is only available on edgeless mode.', - 3000 - ); - return; - } - - const edgelessRootService = rootService as EdgelessRootService; - edgelessRootService?.gfx.tool.setTool('frameNavigator', { + const gfx = this.editor.std.get(GfxControllerIdentifier); + gfx.tool.setTool('frameNavigator', { mode: 'fit', }); } diff --git a/blocksuite/tests-legacy/utils/actions/edgeless.ts b/blocksuite/tests-legacy/utils/actions/edgeless.ts index 2a2bee48be..5eba77b6cf 100644 --- a/blocksuite/tests-legacy/utils/actions/edgeless.ts +++ b/blocksuite/tests-legacy/utils/actions/edgeless.ts @@ -1016,7 +1016,7 @@ export async function deleteAllConnectors(page: Page) { const container = document.querySelector('affine-edgeless-root'); if (!container) throw new Error('container not found'); container.service.crud.getElementsByType('connector').forEach(c => { - container.service.removeElement(c.id); + container.service.crud.removeElement(c.id); }); }); } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts index 16b5a2763b..6711529795 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts @@ -1,18 +1,16 @@ import { ChatHistoryOrder } from '@affine/graphql'; import { BlockSelection, + type BlockStdScope, type EditorHost, TextSelection, } from '@blocksuite/affine/block-std'; -import type { - DocMode, - EdgelessRootService, - ImageSelection, - RootService, -} from '@blocksuite/affine/blocks'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; +import type { DocMode, ImageSelection } from '@blocksuite/affine/blocks'; import { BlocksUtils, DocModeProvider, + EdgelessCRUDIdentifier, EditPropsStore, getSelectedBlocksCommand, NoteDisplayMode, @@ -116,10 +114,10 @@ export async function constructRootChatBlockMessages( return constructUserInfoWithMessages(forkMessages, userInfo); } -function getViewportCenter(mode: DocMode, rootService: RootService) { +function getViewportCenter(mode: DocMode, std: BlockStdScope) { const center = { x: 400, y: 50 }; if (mode === 'page') { - const viewport = rootService.std.get(EditPropsStore).getStorage('viewport'); + const viewport = std.get(EditPropsStore).getStorage('viewport'); if (viewport) { if ('xywh' in viewport) { const bound = Bound.deserialize(viewport.xywh); @@ -132,9 +130,9 @@ function getViewportCenter(mode: DocMode, rootService: RootService) { } } else { // Else we should get latest viewport center from the edgeless root service - const edgelessService = rootService as EdgelessRootService; - center.x = edgelessService.viewport.centerX; - center.y = edgelessService.viewport.centerY; + const viewport = std.get(GfxControllerIdentifier).viewport; + center.x = viewport.centerX; + center.y = viewport.centerY; } return center; @@ -310,18 +308,11 @@ const SAVE_CHAT_TO_BLOCK_ACTION: ChatAction = { return false; } - const rootService = host.std.getService('affine:page'); - const surfaceService = host.std.getService('affine:surface'); - if (!rootService || !surfaceService) return false; - const notificationService = host.std.getOptional(NotificationProvider); const docModeService = host.std.get(DocModeProvider); - const { layer } = surfaceService; + const layer = host.std.get(GfxControllerIdentifier).layer; const curMode = docModeService.getEditorMode() || 'page'; - const viewportCenter = getViewportCenter( - curMode, - rootService as RootService - ); + const viewportCenter = getViewportCenter(curMode, host.std); const newBlockIndex = layer.generateIndex(); // If current mode is not edgeless, switch to edgeless mode first if (curMode !== 'edgeless') { @@ -402,11 +393,9 @@ const ADD_TO_EDGELESS_AS_NOTE = { handler: async (host: EditorHost, content: string) => { reportResponse('result:add-note'); const { doc } = host; - const service = host.std.getService('affine:page'); - if (!service) return; - - const elements = service.selection.selectedElements; + const gfx = host.std.get(GfxControllerIdentifier); + const elements = gfx.selection.selectedElements; const props: { displayMode: NoteDisplayMode; xywh?: SerializedXYWH } = { displayMode: NoteDisplayMode.EdgelessOnly, }; @@ -423,7 +412,7 @@ const ADD_TO_EDGELESS_AS_NOTE = { await insertFromMarkdown(host, content, doc, id, 0); - service.selection.set({ + gfx.selection.set({ elements: [id], editing: false, }); @@ -488,10 +477,6 @@ const CREATE_AS_LINKED_DOC = { return false; } - const service = host.std.getService('affine:page'); - if (!service) { - return false; - } const docModeService = host.std.get(DocModeProvider); const mode = docModeService.getEditorMode(); if (mode !== 'edgeless') { @@ -506,8 +491,9 @@ const CREATE_AS_LINKED_DOC = { const noteId = newDoc.addBlock('affine:note', {}, rootId); await insertFromMarkdown(host, content, newDoc, noteId, 0); + const gfx = host.std.get(GfxControllerIdentifier); // Add a linked doc card to link to the new doc - const elements = service.selection.selectedElements; + const elements = gfx.selection.selectedElements; const width = 364; const height = 390; let x = 0; @@ -523,12 +509,12 @@ const CREATE_AS_LINKED_DOC = { // If the selected elements are not in the viewport, center the linked doc card if (x === Number.POSITIVE_INFINITY || y === Number.POSITIVE_INFINITY) { - const viewportCenter = getViewportCenter(mode, service); + const viewportCenter = getViewportCenter(mode, host.std); x = viewportCenter.x - width / 2; y = viewportCenter.y - height / 2; } - service.crud.addBlock( + host.std.get(EdgelessCRUDIdentifier).addBlock( 'affine:embed-linked-doc', { xywh: `[${x}, ${y}, ${width}, ${height}]`, diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-button.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-button.ts index 97b02f137d..4cec93f1fd 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-button.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-button.ts @@ -4,7 +4,6 @@ import { type EditorHost } from '@blocksuite/affine/block-std'; import { type AIItemGroupConfig, createLitPortal, - EdgelessRootService, HoverController, } from '@blocksuite/affine/blocks'; import { WithDisposable } from '@blocksuite/affine/global/utils'; @@ -14,7 +13,6 @@ import { property, query } from 'lit/decorators.js'; import { ref } from 'lit/directives/ref.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { getRootService } from '../../utils/selection-utils'; import type { ButtonSize } from './ask-ai-icon'; type toggleType = 'hover' | 'click'; @@ -27,14 +25,6 @@ export type AskAIButtonOptions = { }; export class AskAIButton extends WithDisposable(LitElement) { - get _edgeless() { - const rootService = getRootService(this.host); - if (rootService instanceof EdgelessRootService) { - return rootService; - } - return null; - } - static override styles = css` .ask-ai-button { border-radius: 4px; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts index 3c07c9b913..ccfb239882 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts @@ -1,7 +1,7 @@ import { type EditorHost } from '@blocksuite/affine/block-std'; import { type AIItemGroupConfig, - EdgelessRootService, + DocModeProvider, scrollbarStyle, } from '@blocksuite/affine/blocks'; import { WithDisposable } from '@blocksuite/affine/global/utils'; @@ -9,8 +9,6 @@ import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { getRootService } from '../../utils/selection-utils'; - export class AskAIPanel extends WithDisposable(LitElement) { static override styles = css` :host { @@ -50,12 +48,8 @@ export class AskAIPanel extends WithDisposable(LitElement) { @property({ attribute: false }) accessor minWidth = 330; - get _edgeless() { - const rootService = getRootService(this.host); - if (rootService instanceof EdgelessRootService) { - return rootService; - } - return null; + get _isEdgelessMode() { + return this.host.std.get(DocModeProvider).getEditorMode() === 'edgeless'; } get _actionGroups() { @@ -66,7 +60,7 @@ export class AskAIPanel extends WithDisposable(LitElement) { item.showWhen ? item.showWhen( this.host.command.chain(), - this._edgeless ? 'edgeless' : 'page', + this._isEdgelessMode ? 'edgeless' : 'page', this.host ) : true diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts index 478e77fe5b..1adddbb70f 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts @@ -74,10 +74,6 @@ export class ChatCopyMore extends WithDisposable(LitElement) { } `; - private get _rootService() { - return this.host.std.getService('affine:page'); - } - private get _selectionValue() { return this.host.selection.value; } @@ -130,7 +126,6 @@ export class ChatCopyMore extends WithDisposable(LitElement) { } private readonly _notifySuccess = (title: string) => { - if (!this._rootService) return; const notificationService = this.host.std.getOptional(NotificationProvider); notificationService?.notify({ title: title, diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts index 1932df7cb1..3fd2d7abed 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts @@ -1,10 +1,10 @@ import type { EditorHost } from '@blocksuite/affine/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; import type { AffineAIPanelWidget, AIItemConfig, EdgelessCopilotWidget, EdgelessElementToolbarWidget, - EdgelessRootService, MindmapElementModel, ShapeElementModel, } from '@blocksuite/affine/blocks'; @@ -35,17 +35,12 @@ import { AIProvider } from '../provider'; import { reportResponse } from '../utils/action-reporter'; import { getAIPanelWidget } from '../utils/ai-widgets'; import type { AIContext } from '../utils/context'; -import { - getEdgelessCopilotWidget, - getService, - isMindMapRoot, -} from '../utils/edgeless'; +import { getEdgelessCopilotWidget, isMindMapRoot } from '../utils/edgeless'; import { preprocessHtml } from '../utils/html'; import { fetchImageToFile } from '../utils/image'; import { getCopilotSelectedElems, getEdgelessRootFromEditor, - getEdgelessService, getSurfaceElementFromEditor, } from '../utils/selection-utils'; import { createTemplateJob } from '../utils/template-job'; @@ -222,9 +217,9 @@ function insertBelow( ) { insertFromMarkdown(host, markdown, host.doc, parentId, index) .then(() => { - const service = getService(host); + const gfx = host.std.get(GfxControllerIdentifier); - service.selection.set({ + gfx.selection.set({ elements: [parentId], editing: false, }); @@ -398,9 +393,8 @@ export function responseToExpandMindmap(host: EditorHost, ctx: AIContext) { }); setTimeout(() => { - const edgelessService = getEdgelessService(host); - - edgelessService.selection.set({ + const gfx = host.std.get(GfxControllerIdentifier); + gfx.selection.set({ elements: [subtree.element.id], editing: false, }); @@ -410,7 +404,7 @@ export function responseToExpandMindmap(host: EditorHost, ctx: AIContext) { function responseToBrainstormMindmap(host: EditorHost, ctx: AIContext) { const aiPanel = getAIPanelWidget(host); - const edgelessService = getEdgelessService(host); + const gfx = host.std.get(GfxControllerIdentifier); const edgelessCopilot = getEdgelessCopilotWidget(host); const selectionRect = edgelessCopilot.selectionModelRect; const surface = getSurfaceBlock(host.doc); @@ -456,13 +450,13 @@ function responseToBrainstormMindmap(host: EditorHost, ctx: AIContext) { // This is a workaround to make sure mindmap and other microtask are done setTimeout(() => { - edgelessService.viewport.setViewportByBound( + gfx.viewport.setViewportByBound( mindmap.elementBound, [20, 20, 20, 20], true ); - edgelessService.selection.set({ + gfx.selection.set({ elements: [mindmap.tree.element.id], editing: false, }); @@ -508,9 +502,6 @@ async function responseToCreateSlides(host: EditorHost, ctx: AIContext) { const { contents = [], images = [] } = data; if (contents.length === 0) return; - const service = host.std.getService('affine:page'); - if (!service) return; - try { for (let i = 0; i < contents.length; i++) { const image = images[i] || []; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts index f6bea31092..f743438e8a 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts @@ -1,5 +1,6 @@ import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/network-search'; import type { EditorHost } from '@blocksuite/affine/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; import { type AffineAIPanelWidget, type AffineAIPanelWidgetConfig, @@ -38,7 +39,7 @@ import { AIProvider } from './provider'; import { reportResponse } from './utils/action-reporter'; import { getAIPanelWidget } from './utils/ai-widgets'; import { AIContext } from './utils/context'; -import { findNoteBlockModel, getService } from './utils/edgeless'; +import { findNoteBlockModel } from './utils/edgeless'; import { copyTextAnswer } from './utils/editor-actions'; import { getSelections } from './utils/selection-utils'; @@ -93,7 +94,7 @@ function createNewNote(host: EditorHost): AIItemConfig { const newBound = new Bound(bound.x - bound.w - 20, bound.y, bound.w, 72); const doc = host.doc; const panel = getAIPanelWidget(host); - const service = getService(host); + const gfx = host.std.get(GfxControllerIdentifier); doc.transact(() => { assertExists(doc.root); const noteBlockId = doc.addBlock( @@ -101,7 +102,7 @@ function createNewNote(host: EditorHost): AIItemConfig { { xywh: newBound.serialize(), displayMode: NoteDisplayMode.EdgelessOnly, - index: service.generateIndex(), + index: gfx.layer.generateIndex(), }, doc.root.id ); @@ -109,7 +110,7 @@ function createNewNote(host: EditorHost): AIItemConfig { assertExists(panel.answer); insertFromMarkdown(host, panel.answer, doc, noteBlockId) .then(() => { - service.selection.set({ + gfx.selection.set({ elements: [noteBlockId], editing: false, }); @@ -119,7 +120,7 @@ function createNewNote(host: EditorHost): AIItemConfig { if (!newNote || !matchModels(newNote, [NoteBlockModel])) return; const newNoteBound = Bound.deserialize(newNote.xywh); const bounds = [bound, newNoteBound]; - service.gfx.fitToScreen({ + gfx.fitToScreen({ bounds, padding: [20, 20, 20, 20], }); diff --git a/packages/frontend/core/src/blocksuite/presets/ai/mini-mindmap/surface-block.ts b/packages/frontend/core/src/blocksuite/presets/ai/mini-mindmap/surface-block.ts index 0372f0c930..b16fcb48d6 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/mini-mindmap/surface-block.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/mini-mindmap/surface-block.ts @@ -16,7 +16,7 @@ import type { Bound } from '@blocksuite/affine/global/utils'; import { html } from 'lit'; import { query } from 'lit/decorators.js'; -import type { MindmapService } from './mindmap-service.js'; +import { MindmapService } from './mindmap-service.js'; export class MindmapSurfaceBlock extends BlockComponent { renderer?: CanvasRenderer; @@ -30,7 +30,7 @@ export class MindmapSurfaceBlock extends BlockComponent { } get mindmapService() { - return this.std.getService('affine:page') as unknown as MindmapService; + return this.std.get(MindmapService); } get viewport() { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts index 65352c4e0b..401f057b9b 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts @@ -4,7 +4,8 @@ import { CanvasElementType, ConnectorMode, DocModeProvider, - type EdgelessRootService, + EdgelessCRUDIdentifier, + getSurfaceBlock, NotificationProvider, TelemetryProvider, } from '@blocksuite/affine/blocks'; @@ -33,10 +34,6 @@ import { calcChildBound } from './utils'; export class AIChatBlockPeekView extends LitElement { static override styles = PeekViewStyles; - private get _rootService() { - return this.host.std.getService('affine:page'); - } - private get _modeService() { return this.host.std.get(DocModeProvider); } @@ -172,9 +169,10 @@ export class AIChatBlockPeekView extends LitElement { return; } - const edgelessService = this._rootService as EdgelessRootService; - const bound = calcChildBound(this.parentModel, edgelessService); - const aiChatBlockId = edgelessService.crud.addBlock( + const bound = calcChildBound(this.parentModel, this.host.std); + + const crud = this.host.std.get(EdgelessCRUDIdentifier); + const aiChatBlockId = crud.addBlock( 'affine:embed-ai-chat', { xywh: bound.serialize(), @@ -193,7 +191,7 @@ export class AIChatBlockPeekView extends LitElement { this.updateContext({ currentChatBlockId: aiChatBlockId }); // Connect the parent chat block to the AI chat block - edgelessService.crud.addElement(CanvasElementType.CONNECTOR, { + crud.addElement(CanvasElementType.CONNECTOR, { mode: ConnectorMode.Curve, controllers: [], source: { id: this.parentChatBlockId }, @@ -249,7 +247,6 @@ export class AIChatBlockPeekView extends LitElement { * Clean current chat messages and delete the newly created AI chat block */ cleanCurrentChatHistories = async () => { - if (!this._rootService) return; const notificationService = this.host.std.getOptional(NotificationProvider); if (!notificationService) return; @@ -275,18 +272,17 @@ export class AIChatBlockPeekView extends LitElement { } if (currentChatBlockId) { - const edgelessService = this._rootService as EdgelessRootService; + const surface = getSurfaceBlock(doc); + const crud = this.host.std.get(EdgelessCRUDIdentifier); const chatBlock = doc.getBlock(currentChatBlockId)?.model; if (chatBlock) { - const connectors = edgelessService.getConnectors( - chatBlock as AIChatBlockModel - ); + const connectors = surface?.getConnectors(chatBlock.id); doc.transact(() => { // Delete the AI chat block - edgelessService.removeElement(currentChatBlockId); + crud.removeElement(currentChatBlockId); // Delete the connectors - connectors.forEach(connector => { - edgelessService.removeElement(connector.id); + connectors?.forEach(connector => { + crud.removeElement(connector.id); }); }); } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/utils.ts b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/utils.ts index 1384d299d8..da9dea5d47 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/utils.ts @@ -1,4 +1,8 @@ -import type { EdgelessRootService } from '@blocksuite/affine/blocks'; +import type { BlockStdScope } from '@blocksuite/affine/block-std'; +import { + EdgelessCRUDIdentifier, + getSurfaceBlock, +} from '@blocksuite/affine/blocks'; import { Bound } from '@blocksuite/affine/global/utils'; import { @@ -19,18 +23,19 @@ import { */ export function calcChildBound( parentModel: AIChatBlockModel, - service: EdgelessRootService + std: BlockStdScope ) { + const surface = getSurfaceBlock(std.store); + const crud = std.get(EdgelessCRUDIdentifier); const parentXYWH = Bound.deserialize(parentModel.xywh); const { x: parentX, y: parentY, w: parentWidth } = parentXYWH; - const connectors = service.getConnectors(parentModel.id); + const connectors = surface?.getConnectors(parentModel.id); const gapX = CHAT_BLOCK_WIDTH; const gapY = 60; const defaultX = parentX + parentWidth + gapX; const defaultY = parentY; - - if (!connectors.length) { + if (!connectors?.length) { return new Bound(defaultX, defaultY, CHAT_BLOCK_WIDTH, CHAT_BLOCK_HEIGHT); } else { // Filter out the connectors which source is the parent block @@ -41,7 +46,7 @@ export function calcChildBound( const targetBlocks = childConnectors .map(connector => connector.target.id) .filter(id => id !== undefined) - .map(id => service.crud.getElementById(id)) + .map(id => crud.getElementById(id)) .filter(block => !!block); if (targetBlocks.length) { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts index 747db2ef59..8081b46b3c 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts @@ -1,5 +1,5 @@ import type { EditorHost } from '@blocksuite/affine/block-std'; -import type { EdgelessRootService } from '@blocksuite/affine/blocks'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; import type { BlockSnapshot } from '@blocksuite/affine/store'; import { markdownToSnapshot } from '../../_common'; @@ -13,11 +13,10 @@ import { } from './template'; export const PPTBuilder = (host: EditorHost) => { - const service = host.std.getService('affine:page'); + const gfx = host.std.get(GfxControllerIdentifier); const docs: PPTDoc[] = []; const contents: unknown[] = []; const allImages: TemplateImage[][] = []; - if (!service) return; const addDoc = async (block: BlockSnapshot) => { const sections = block.children.map(v => { @@ -62,7 +61,7 @@ export const PPTBuilder = (host: EditorHost) => { const block = snapshot.snapshot.content[0]; for (const child of block.children) { await addDoc(child); - service.gfx.fitToScreen(); + gfx.fitToScreen(); } } catch (e) { console.error(e); diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts index 3ae09aba36..29a01cba3c 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts @@ -3,7 +3,6 @@ import type { GfxModel } from '@blocksuite/affine/block-std/gfx'; import { AFFINE_EDGELESS_COPILOT_WIDGET, type EdgelessCopilotWidget, - type EdgelessRootService, matchModels, MindmapElementModel, NoteBlockModel, @@ -43,14 +42,6 @@ export function isMindmapChild(ele: GfxModel) { return ele?.group instanceof MindmapElementModel && !isMindMapRoot(ele); } -export function getService(host: EditorHost) { - const edgelessService = host.std.getService( - 'affine:page' - ) as EdgelessRootService; - - return edgelessService; -} - export function getEdgelessCopilotWidget( host: EditorHost ): EdgelessCopilotWidget { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts index 9aad9fadf2..ce6ee1ac40 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts @@ -1,10 +1,12 @@ import { type EditorHost, TextSelection } from '@blocksuite/affine/block-std'; -import type { GfxModel } from '@blocksuite/affine/block-std/gfx'; +import { + GfxControllerIdentifier, + type GfxModel, +} from '@blocksuite/affine/block-std/gfx'; import { BlocksUtils, type CopilotTool, DatabaseBlockModel, - EdgelessRootService, type FrameBlockModel, getBlockSelectionsCommand, getImageSelectionsCommand, @@ -22,11 +24,7 @@ import { } from '@blocksuite/affine/store'; import { getContentFromSlice } from '../../_common'; -import { getEdgelessCopilotWidget, getService } from './edgeless'; - -export const getRootService = (host: EditorHost) => { - return host.std.getService('affine:page'); -}; +import { getEdgelessCopilotWidget } from './edgeless'; export function getEdgelessRootFromEditor(editor: EditorHost) { const edgelessRoot = editor.getElementsByTagName('affine-edgeless-root')[0]; @@ -36,14 +34,6 @@ export function getEdgelessRootFromEditor(editor: EditorHost) { } return edgelessRoot; } -export function getEdgelessService(editor: EditorHost) { - const rootService = editor.std.getService('affine:page'); - if (rootService instanceof EdgelessRootService) { - return rootService; - } - alert('Please switch to edgeless mode'); - throw new Error('Please open switch to edgeless mode'); -} export async function selectedToCanvas(host: EditorHost) { const edgelessRoot = getEdgelessRootFromEditor(host); @@ -287,15 +277,15 @@ export const getSelectedNoteAnchor = (host: EditorHost, id: string) => { }; export function getCopilotSelectedElems(host: EditorHost): GfxModel[] { - const service = getService(host); + const gfx = host.std.get(GfxControllerIdentifier); const copilotWidget = getEdgelessCopilotWidget(host); if (copilotWidget.visible) { - const currentTool = service.gfx.tool.currentTool$.peek() as CopilotTool; + const currentTool = gfx.tool.currentTool$.peek() as CopilotTool; return currentTool?.selectedElements ?? []; } - return service.selection.selectedElements; + return gfx.selection.selectedElements; } export const imageCustomInput = async (host: EditorHost) => { diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/copy-as-image.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/copy-as-image.ts index c61ceef7f1..55aab238bb 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/copy-as-image.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/copy-as-image.ts @@ -9,14 +9,12 @@ import { I18n } from '@affine/i18n'; import type { BlockStdScope } from '@blocksuite/affine/block-std'; import { type GfxBlockElementModel, + GfxControllerIdentifier, type GfxModel, GfxPrimitiveElementModel, isGfxGroupCompatibleModel, } from '@blocksuite/affine/block-std/gfx'; -import type { - EdgelessRootService, - MenuContext, -} from '@blocksuite/affine/blocks'; +import type { MenuContext } from '@blocksuite/affine/blocks'; import { Bound, getCommonBound } from '@blocksuite/affine/global/utils'; import { CopyAsImgaeIcon } from '@blocksuite/icons/lit'; import type { FrameworkProvider } from '@toeverything/infra'; @@ -135,11 +133,9 @@ export function createCopyAsPngMenuItem(framework: FrameworkProvider) { return; } - const service = - ctx.host.std.getService('affine:page'); - if (!service) return; + const gfx = ctx.host.std.get(GfxControllerIdentifier); - let selected = service.selection.selectedElements; + let selected = gfx.selection.selectedElements; // select mindmap if root node selected const maybeMindmap = selected[0]; const mindmapId = maybeMindmap.group?.id; @@ -148,31 +144,31 @@ export function createCopyAsPngMenuItem(framework: FrameworkProvider) { mindmapId && (isMindMapRoot(maybeMindmap) || isMindmapChild(maybeMindmap)) ) { - service.gfx.selection.set({ elements: [mindmapId] }); + gfx.selection.set({ elements: [mindmapId] }); } // select bound - selected = service.selection.selectedElements; + selected = gfx.selection.selectedElements; const elements = withDescendantElements(selected); const bounds = elements.map(element => Bound.deserialize(element.xywh)); const bound = getCommonBound(bounds); if (!bound) return; - const { zoom } = service.viewport; + const { zoom } = gfx.viewport; const exBound = expandBound(bound, MARGIN * zoom); // fit to screen if ( - !isInside(service.viewport.viewportBounds, exBound) || - service.viewport.zoom < 1 + !isInside(gfx.viewport.viewportBounds, exBound) || + gfx.viewport.zoom < 1 ) { - service.viewport.setViewportByBound(bound, [20, 20, 20, 20], false); - if (service.viewport.zoom > 1) { - service.viewport.setZoom(1); + gfx.viewport.setViewportByBound(bound, [20, 20, 20, 20], false); + if (gfx.viewport.zoom > 1) { + gfx.viewport.setZoom(1); } } // hide unselected overlap elements - const overlapElements = service.gfx.gfxElements.filter(ele => { + const overlapElements = gfx.gfxElements.filter(ele => { const eleBound = Bound.deserialize(ele.xywh); const exEleBound = expandBound(eleBound, MARGIN * zoom); const isSelected = elements.includes(ele); @@ -190,14 +186,14 @@ export function createCopyAsPngMenuItem(framework: FrameworkProvider) { if (!apis) return; try { const domRect = getSelectedRect(); - const { zoom } = service.viewport; + const { zoom } = gfx.viewport; const isFrameSelected = selected.length === 1 && (selected[0] as GfxBlockElementModel).flavour === 'affine:frame'; const margin = isFrameSelected ? -2 : MARGIN * zoom; - service.selection.clear(); - // eslint-disable-next-line @typescript-eslint/no-floating-promises + gfx.selection.clear(); + apis.ui .captureArea({ x: domRect.left - margin, diff --git a/packages/frontend/core/src/components/hooks/affine/use-share-url.ts b/packages/frontend/core/src/components/hooks/affine/use-share-url.ts index 0ec4b405d1..ca56bfb560 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-share-url.ts +++ b/packages/frontend/core/src/components/hooks/affine/use-share-url.ts @@ -5,10 +5,12 @@ import { copyTextToClipboard } from '@affine/core/utils/clipboard'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; import { type EditorHost } from '@blocksuite/affine/block-std'; -import { GfxBlockElementModel } from '@blocksuite/affine/block-std/gfx'; +import { + GfxBlockElementModel, + GfxControllerIdentifier, +} from '@blocksuite/affine/block-std/gfx'; import { type DocMode, - type EdgelessRootService, getBlockSelectionsCommand, getImageSelectionsCommand, getSelectedModelsCommand, @@ -87,10 +89,9 @@ export const getSelectedNodes = ( } if (mode === 'edgeless') { - const service = std.getService('affine:page'); - if (!service) return result; + const { selection } = std.get(GfxControllerIdentifier); - for (const element of service.selection.selectedElements) { + for (const element of selection.selectedElements) { if (element instanceof GfxBlockElementModel) { blockIds.push(element.id); } else { diff --git a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/shape.tsx b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/shape.tsx index 42ede7c63d..36c456edb8 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/shape.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/shape.tsx @@ -9,13 +9,10 @@ import { SettingRow } from '@affine/component/setting-components'; import { EditorSettingService } from '@affine/core/modules/editor-setting'; import { useI18n } from '@affine/i18n'; import type { EditorHost } from '@blocksuite/affine/block-std'; -import type { - EdgelessRootService, - ShapeElementModel, - ShapeName, -} from '@blocksuite/affine/blocks'; +import type { ShapeElementModel, ShapeName } from '@blocksuite/affine/blocks'; import { DefaultTheme, + EdgelessCRUDIdentifier, FontFamily, FontFamilyMap, FontStyle, @@ -354,18 +351,16 @@ export const ShapeSettings = () => { const firstUpdate = useCallback( (doc: Store, editorHost: EditorHost) => { - const edgelessService = editorHost.std.getService( - 'affine:page' - ) as EdgelessRootService; const surface = getSurfaceBlock(doc); if (!surface) return; + const crud = editorHost.std.get(EdgelessCRUDIdentifier); doc.readonly = false; surface.getElementsByType('shape').forEach(node => { const shape = node as ShapeElementModel; const { shapeType, radius } = shape; const shapeName = getShapeName(shapeType, radius); const props = editorSetting.get(`shape:${shapeName}`); - edgelessService.crud.updateElement(shape.id, props); + crud.updateElement(shape.id, props); }); doc.readonly = true; }, diff --git a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx index f652fe73e9..a63e3e870c 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx @@ -4,18 +4,20 @@ import { EditorSettingService } from '@affine/core/modules/editor-setting'; import { AppThemeService } from '@affine/core/modules/theme'; import type { EditorHost } from '@blocksuite/affine/block-std'; import { + BlockServiceIdentifier, BlockStdScope, LifeCycleWatcher, StdIdentifier, } from '@blocksuite/affine/block-std'; -import type { GfxPrimitiveElementModel } from '@blocksuite/affine/block-std/gfx'; -import type { - EdgelessRootService, - ThemeExtension, -} from '@blocksuite/affine/blocks'; +import { + GfxControllerIdentifier, + type GfxPrimitiveElementModel, +} from '@blocksuite/affine/block-std/gfx'; +import type { ThemeExtension } from '@blocksuite/affine/blocks'; import { ColorScheme, createSignalFromObservable, + EdgelessCRUDIdentifier, SpecProvider, ThemeExtensionIdentifier, } from '@blocksuite/affine/blocks'; @@ -72,14 +74,12 @@ export const EdgelessSnapshot = (props: Props) => { const editorHost = editorHostRef.current; const doc = docRef.current; if (!editorHost || !doc) return; - const edgelessService = editorHost.std.getService( - 'affine:page' - ) as EdgelessRootService; + const crud = editorHost.std.get(EdgelessCRUDIdentifier); const elements = getElements(doc); const props = editorSetting.get(keyName) as any; doc.readonly = false; elements.forEach(element => { - edgelessService.crud.updateElement(element.id, props); + crud.updateElement(element.id, props); }); doc.readonly = true; }, [editorSetting, getElements, keyName]); @@ -107,9 +107,10 @@ export const EdgelessSnapshot = (props: Props) => { } // refresh viewport - const edgelessService = editorHost.std.getService( - 'affine:page' - ) as EdgelessRootService; + const edgelessService = editorHost.std.get( + BlockServiceIdentifier('affine:page') + ); + const gfx = editorHost.std.get(GfxControllerIdentifier); edgelessService.specSlots.viewConnected.once(({ component }) => { const edgelessBlock = component as any; doc.readonly = false; @@ -121,7 +122,7 @@ export const EdgelessSnapshot = (props: Props) => { doc.deleteBlock(frame); } const bound = boundMap.get(docName); - bound && edgelessService.viewport.setViewportByBound(bound); + bound && gfx.viewport.setViewportByBound(bound); doc.readonly = true; }); diff --git a/packages/frontend/core/src/modules/editor/entities/editor.ts b/packages/frontend/core/src/modules/editor/entities/editor.ts index b0ea62688a..ecd65673f4 100644 --- a/packages/frontend/core/src/modules/editor/entities/editor.ts +++ b/packages/frontend/core/src/modules/editor/entities/editor.ts @@ -1,7 +1,7 @@ import type { DefaultOpenProperty } from '@affine/core/components/doc-properties'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; import { type DocMode, - EdgelessRootService, FeatureFlagService as BSFeatureFlagService, HighlightSelection, type ReferenceParams, @@ -73,13 +73,11 @@ export class Editor extends Entity { isPresenting$ = new LiveData(false); togglePresentation() { - const edgelessRootService = - this.editorContainer$.value?.host?.std.getService( - 'affine:page' - ) as EdgelessRootService; - if (!edgelessRootService) return; - - edgelessRootService.gfx.tool.setTool({ + const gfx = this.editorContainer$.value?.host?.std.get( + GfxControllerIdentifier + ); + if (!gfx) return; + gfx.tool.setTool({ type: !this.isPresenting$.value ? 'frameNavigator' : 'default', }); } @@ -200,7 +198,7 @@ export class Editor extends Entity { this.editorContainer$.next(editorContainer); const unsubs: (() => void)[] = []; - const rootService = editorContainer.host?.std.getService('affine:page'); + const gfx = editorContainer.host?.std.get(GfxControllerIdentifier); // ----- Scroll Position and Selection ----- // if we have default scroll position, we should restore it @@ -209,9 +207,9 @@ export class Editor extends Entity { } else if ( this.mode$.value === 'edgeless' && this.scrollPosition.edgeless && - rootService instanceof EdgelessRootService + gfx ) { - rootService.viewport.setViewport(this.scrollPosition.edgeless.zoom, [ + gfx.viewport.setViewport(this.scrollPosition.edgeless.zoom, [ this.scrollPosition.edgeless.centerX, this.scrollPosition.edgeless.centerY, ]); @@ -253,14 +251,11 @@ export class Editor extends Entity { if (this.mode$.value === 'page' && scrollViewport) { this.scrollPosition.page = scrollViewport.scrollTop; this.workbenchView?.setScrollPosition(scrollViewport.scrollTop); - } else if ( - this.mode$.value === 'edgeless' && - rootService instanceof EdgelessRootService - ) { + } else if (this.mode$.value === 'edgeless' && gfx) { const pos = { - centerX: rootService.viewport.centerX, - centerY: rootService.viewport.centerY, - zoom: rootService.viewport.zoom, + centerX: gfx.viewport.centerX, + centerY: gfx.viewport.centerY, + zoom: gfx.viewport.zoom, }; this.scrollPosition.edgeless = pos; this.workbenchView?.setScrollPosition(pos); @@ -270,10 +265,8 @@ export class Editor extends Entity { unsubs.push(() => { scrollViewport?.removeEventListener('scroll', saveScrollPosition); }); - if (rootService instanceof EdgelessRootService) { - unsubs.push( - rootService.viewport.viewportUpdated.on(saveScrollPosition).dispose - ); + if (gfx) { + unsubs.push(gfx.viewport.viewportUpdated.on(saveScrollPosition).dispose); } // update selection when focusAt$ changed diff --git a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx index c255bf7b28..17504ff3b8 100644 --- a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx @@ -10,10 +10,8 @@ import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline- import { PageNotFound } from '@affine/core/desktop/pages/404'; import { EditorService } from '@affine/core/modules/editor'; import { DebugLogger } from '@affine/debug'; -import { - type EdgelessRootService, - RefNodeSlotsProvider, -} from '@blocksuite/affine/blocks'; +import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx'; +import { RefNodeSlotsProvider } from '@blocksuite/affine/blocks'; import { Bound, type Disposable, @@ -46,25 +44,22 @@ function fitViewport( throw new Error('editor host is not ready'); } - const rootService = - editor.host.std.getService('affine:page'); - if (!rootService) { - return; - } - rootService.viewport.onResize(); + const gfx = editor.host.std.get(GfxControllerIdentifier); + const viewport = gfx.viewport; + viewport.onResize(); if (xywh) { - const viewport = { + const newViewport = { xywh: xywh, padding: [60, 20, 20, 20] as [number, number, number, number], }; - rootService.viewport.setViewportByBound( - Bound.deserialize(viewport.xywh), - viewport.padding, + viewport.setViewportByBound( + Bound.deserialize(newViewport.xywh), + newViewport.padding, false ); } else { - rootService.gfx.fitToScreen({ + gfx.fitToScreen({ smooth: false, }); }