From 9d9089934497c062ae6ddcca812b5614c30c97cf Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Thu, 24 Apr 2025 03:21:53 +0000 Subject: [PATCH] feat(editor): group gfx extension (#11950) Closes: BS-3208 ## Summary by CodeRabbit - **New Features** - Introduced a new group view extension, enhancing how group elements are handled and displayed. - Added new store and view modules for group-related features, improving modularity and integration. - **Refactor** - Updated the group element architecture to use extension-based registration for views, toolbars, and effects. - Simplified and reorganized exports for group and text modules. - **Chores** - Updated dependencies and project references to improve build consistency and compatibility. --- blocksuite/affine/all/package.json | 4 +- blocksuite/affine/all/src/extensions/store.ts | 2 + blocksuite/affine/all/src/extensions/view.ts | 3 ++ .../all/src/gfx/{group.ts => group/index.ts} | 0 blocksuite/affine/all/src/gfx/group/store.ts | 1 + blocksuite/affine/all/src/gfx/group/view.ts | 1 + .../blocks/root/src/common-specs/index.ts | 16 +------- .../src/edgeless/configs/toolbar/index.ts | 3 -- blocksuite/affine/blocks/root/src/effects.ts | 2 - .../blocks/surface/src/surface-model.ts | 5 --- blocksuite/affine/gfx/connector/src/view.ts | 4 ++ blocksuite/affine/gfx/group/package.json | 5 ++- .../affine/gfx/group/src/element-view.ts | 24 ++++++++++++ .../group/src/group-watcher.ts} | 16 ++++++-- blocksuite/affine/gfx/group/src/index.ts | 2 +- blocksuite/affine/gfx/group/src/store.ts | 21 +++++++++++ blocksuite/affine/gfx/group/src/view.ts | 37 ++++++++++--------- blocksuite/affine/gfx/group/tsconfig.json | 1 + .../gfx/text/src/{view.ts => element-view.ts} | 0 blocksuite/affine/gfx/text/src/index.ts | 2 +- tools/utils/src/workspace.gen.ts | 1 + yarn.lock | 1 + 22 files changed, 101 insertions(+), 50 deletions(-) rename blocksuite/affine/all/src/gfx/{group.ts => group/index.ts} (100%) create mode 100644 blocksuite/affine/all/src/gfx/group/store.ts create mode 100644 blocksuite/affine/all/src/gfx/group/view.ts create mode 100644 blocksuite/affine/gfx/group/src/element-view.ts rename blocksuite/affine/{blocks/surface/src/watchers/group.ts => gfx/group/src/group-watcher.ts} (60%) create mode 100644 blocksuite/affine/gfx/group/src/store.ts rename blocksuite/affine/gfx/text/src/{view.ts => element-view.ts} (100%) diff --git a/blocksuite/affine/all/package.json b/blocksuite/affine/all/package.json index fa5ddf4be7..373d14a687 100644 --- a/blocksuite/affine/all/package.json +++ b/blocksuite/affine/all/package.json @@ -188,7 +188,9 @@ "./gfx/connector": "./src/gfx/connector/index.ts", "./gfx/connector/store": "./src/gfx/connector/store.ts", "./gfx/connector/view": "./src/gfx/connector/view.ts", - "./gfx/group": "./src/gfx/group.ts", + "./gfx/group": "./src/gfx/group/index.ts", + "./gfx/group/store": "./src/gfx/group/store.ts", + "./gfx/group/view": "./src/gfx/group/view.ts", "./gfx/template": "./src/gfx/template/index.ts", "./gfx/template/view": "./src/gfx/template/view.ts", "./gfx/turbo-renderer": "./src/gfx/turbo-renderer.ts", diff --git a/blocksuite/affine/all/src/extensions/store.ts b/blocksuite/affine/all/src/extensions/store.ts index 297ce88f3c..cb2cb5647d 100644 --- a/blocksuite/affine/all/src/extensions/store.ts +++ b/blocksuite/affine/all/src/extensions/store.ts @@ -17,6 +17,7 @@ import { SurfaceRefStoreExtension } from '@blocksuite/affine-block-surface-ref/s import { TableStoreExtension } from '@blocksuite/affine-block-table/store'; import { BrushStoreExtension } from '@blocksuite/affine-gfx-brush/store'; import { ConnectorStoreExtension } from '@blocksuite/affine-gfx-connector/store'; +import { GroupStoreExtension } from '@blocksuite/affine-gfx-group/store'; import { MindmapStoreExtension } from '@blocksuite/affine-gfx-mindmap/store'; import { ShapeStoreExtension } from '@blocksuite/affine-gfx-shape/store'; import { FootnoteStoreExtension } from '@blocksuite/affine-inline-footnote/store'; @@ -57,6 +58,7 @@ export function getInternalStoreExtensions() { ShapeStoreExtension, MindmapStoreExtension, ConnectorStoreExtension, + GroupStoreExtension, MigratingStoreExtension, ]; diff --git a/blocksuite/affine/all/src/extensions/view.ts b/blocksuite/affine/all/src/extensions/view.ts index 7708d53cbc..a782e8489e 100644 --- a/blocksuite/affine/all/src/extensions/view.ts +++ b/blocksuite/affine/all/src/extensions/view.ts @@ -17,6 +17,7 @@ import { SurfaceRefViewExtension } from '@blocksuite/affine-block-surface-ref/vi import { TableViewExtension } from '@blocksuite/affine-block-table/view'; import { BrushViewExtension } from '@blocksuite/affine-gfx-brush/view'; import { ConnectorViewExtension } from '@blocksuite/affine-gfx-connector/view'; +import { GroupViewExtension } from '@blocksuite/affine-gfx-group/view'; import { MindmapViewExtension } from '@blocksuite/affine-gfx-mindmap/view'; import { NoteViewExtension as GfxNoteViewExtension } from '@blocksuite/affine-gfx-note/view'; import { ShapeViewExtension } from '@blocksuite/affine-gfx-shape/view'; @@ -32,11 +33,13 @@ import { MigratingViewExtension } from './migrating-view'; export function getInternalViewExtensions() { return [ + // Gfx GfxNoteViewExtension, BrushViewExtension, ShapeViewExtension, MindmapViewExtension, ConnectorViewExtension, + GroupViewExtension, TemplateViewExtension, // Block diff --git a/blocksuite/affine/all/src/gfx/group.ts b/blocksuite/affine/all/src/gfx/group/index.ts similarity index 100% rename from blocksuite/affine/all/src/gfx/group.ts rename to blocksuite/affine/all/src/gfx/group/index.ts diff --git a/blocksuite/affine/all/src/gfx/group/store.ts b/blocksuite/affine/all/src/gfx/group/store.ts new file mode 100644 index 0000000000..1816263007 --- /dev/null +++ b/blocksuite/affine/all/src/gfx/group/store.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-gfx-group/store'; diff --git a/blocksuite/affine/all/src/gfx/group/view.ts b/blocksuite/affine/all/src/gfx/group/view.ts new file mode 100644 index 0000000000..2b22344b28 --- /dev/null +++ b/blocksuite/affine/all/src/gfx/group/view.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-gfx-group/view'; diff --git a/blocksuite/affine/blocks/root/src/common-specs/index.ts b/blocksuite/affine/blocks/root/src/common-specs/index.ts index 32a12a7dcd..070f11cb16 100644 --- a/blocksuite/affine/blocks/root/src/common-specs/index.ts +++ b/blocksuite/affine/blocks/root/src/common-specs/index.ts @@ -1,12 +1,4 @@ import { FileDropExtension } from '@blocksuite/affine-components/drop-indicator'; -import { - ConnectorElementRendererExtension, - ConnectorElementView, -} from '@blocksuite/affine-gfx-connector'; -import { - GroupElementRendererExtension, - GroupElementView, -} from '@blocksuite/affine-gfx-group'; import { TextElementRendererExtension, TextElementView, @@ -42,16 +34,10 @@ import { viewportOverlayWidget } from './widgets'; * Because in some cases we need to create edgeless elements in page mode. * And these view may contain some logic when elements initialize. */ -const EdgelessElementViews = [ - ConnectorElementView, - GroupElementView, - TextElementView, -]; +const EdgelessElementViews = [TextElementView]; export const EdgelessElementRendererExtension: ExtensionType[] = [ TextElementRendererExtension, - ConnectorElementRendererExtension, - GroupElementRendererExtension, ]; export const CommonSpecs: ExtensionType[] = [ diff --git a/blocksuite/affine/blocks/root/src/edgeless/configs/toolbar/index.ts b/blocksuite/affine/blocks/root/src/edgeless/configs/toolbar/index.ts index 5bb6de023d..0b3168fe6c 100644 --- a/blocksuite/affine/blocks/root/src/edgeless/configs/toolbar/index.ts +++ b/blocksuite/affine/blocks/root/src/edgeless/configs/toolbar/index.ts @@ -1,4 +1,3 @@ -import { groupToolbarExtension } from '@blocksuite/affine-gfx-group'; import { textToolbarExtension } from '@blocksuite/affine-gfx-text'; import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services'; import { BlockFlavourIdentifier } from '@blocksuite/std'; @@ -7,8 +6,6 @@ import type { ExtensionType } from '@blocksuite/store'; import { builtinLockedToolbarConfig, builtinMiscToolbarConfig } from './misc'; export const EdgelessElementToolbarExtension: ExtensionType[] = [ - groupToolbarExtension, - textToolbarExtension, ToolbarModuleExtension({ diff --git a/blocksuite/affine/blocks/root/src/effects.ts b/blocksuite/affine/blocks/root/src/effects.ts index 2b6c79e92e..23445602c2 100644 --- a/blocksuite/affine/blocks/root/src/effects.ts +++ b/blocksuite/affine/blocks/root/src/effects.ts @@ -1,4 +1,3 @@ -import { effects as gfxGroupEffects } from '@blocksuite/affine-gfx-group/effects'; import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects'; import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widget-edgeless-toolbar/effects'; import { effects as widgetMobileToolbarEffects } from '@blocksuite/affine-widget-keyboard-toolbar/effects'; @@ -73,7 +72,6 @@ function registerRootComponents() { function registerGfxEffects() { gfxCanvasTextEffects(); - gfxGroupEffects(); } function registerWidgets() { diff --git a/blocksuite/affine/blocks/surface/src/surface-model.ts b/blocksuite/affine/blocks/surface/src/surface-model.ts index 4e743f5aaf..a655ed9277 100644 --- a/blocksuite/affine/blocks/surface/src/surface-model.ts +++ b/blocksuite/affine/blocks/surface/src/surface-model.ts @@ -11,7 +11,6 @@ import * as Y from 'yjs'; import { elementsCtorMap } from './element-model/index.js'; import { surfaceMiddlewareIdentifier } from './extensions/surface-middleware.js'; import { SurfaceBlockTransformer } from './surface-transformer.js'; -import { groupRelationWatcher } from './watchers/group.js'; export const SurfaceBlockSchema = defineBlockSchema({ flavour: 'affine:surface', @@ -50,10 +49,6 @@ export class SurfaceBlockModel extends BaseSurfaceModel { .forEach(({ middleware }) => { this._disposables.add(middleware(this)); }); - - [groupRelationWatcher(this)].forEach(disposable => - this._disposables.add(disposable) - ); } getConnectors(id: string) { diff --git a/blocksuite/affine/gfx/connector/src/view.ts b/blocksuite/affine/gfx/connector/src/view.ts index fcd16aef5d..4df717af20 100644 --- a/blocksuite/affine/gfx/connector/src/view.ts +++ b/blocksuite/affine/gfx/connector/src/view.ts @@ -6,9 +6,11 @@ import { import { ConnectionOverlay } from './connector-manager'; import { ConnectorTool } from './connector-tool'; import { effects } from './effects'; +import { ConnectorElementRendererExtension } from './element-renderer'; import { ConnectorFilter } from './element-transform'; import { connectorToolbarExtension } from './toolbar/config'; import { connectorQuickTool } from './toolbar/quick-tool'; +import { ConnectorElementView } from './view/view'; export class ConnectorViewExtension extends ViewExtensionProvider { override name = 'affine-connector-gfx'; @@ -20,6 +22,8 @@ export class ConnectorViewExtension extends ViewExtensionProvider { override setup(context: ViewExtensionContext) { super.setup(context); + context.register(ConnectorElementView); + context.register(ConnectorElementRendererExtension); if (this.isEdgeless(context.scope)) { context.register(ConnectorTool); context.register(ConnectorFilter); diff --git a/blocksuite/affine/gfx/group/package.json b/blocksuite/affine/gfx/group/package.json index 794b7d50aa..9460ea56b6 100644 --- a/blocksuite/affine/gfx/group/package.json +++ b/blocksuite/affine/gfx/group/package.json @@ -12,6 +12,7 @@ "dependencies": { "@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-components": "workspace:*", + "@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-gfx-text": "workspace:*", "@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-rich-text": "workspace:*", @@ -34,7 +35,9 @@ }, "exports": { ".": "./src/index.ts", - "./effects": "./src/effects.ts" + "./effects": "./src/effects.ts", + "./view": "./src/view.ts", + "./store": "./src/store.ts" }, "files": [ "src", diff --git a/blocksuite/affine/gfx/group/src/element-view.ts b/blocksuite/affine/gfx/group/src/element-view.ts new file mode 100644 index 0000000000..721df9ecf5 --- /dev/null +++ b/blocksuite/affine/gfx/group/src/element-view.ts @@ -0,0 +1,24 @@ +import type { GroupElementModel } from '@blocksuite/affine-model'; +import { GfxElementModelView } from '@blocksuite/std/gfx'; + +import { mountGroupTitleEditor } from './text/edgeless-group-title-editor'; + +export class GroupElementView extends GfxElementModelView { + static override type: string = 'group'; + + override onCreated(): void { + super.onCreated(); + + this._initDblClickToEdit(); + } + + private _initDblClickToEdit(): void { + this.on('dblclick', () => { + const edgeless = this.std.view.getBlock(this.std.store.root!.id); + + if (edgeless && !this.model.isLocked()) { + mountGroupTitleEditor(this.model, edgeless); + } + }); + } +} diff --git a/blocksuite/affine/blocks/surface/src/watchers/group.ts b/blocksuite/affine/gfx/group/src/group-watcher.ts similarity index 60% rename from blocksuite/affine/blocks/surface/src/watchers/group.ts rename to blocksuite/affine/gfx/group/src/group-watcher.ts index 5940cec5a8..12b3c255e2 100644 --- a/blocksuite/affine/blocks/surface/src/watchers/group.ts +++ b/blocksuite/affine/gfx/group/src/group-watcher.ts @@ -1,8 +1,11 @@ -import { SurfaceGroupLikeModel } from '../element-model/base.js'; -import type { SurfaceMiddleware } from '../extensions/surface-middleware.js'; -import type { SurfaceBlockModel } from '../surface-model.js'; +import { + type SurfaceBlockModel, + SurfaceGroupLikeModel, + type SurfaceMiddleware, + surfaceMiddlewareExtension, +} from '@blocksuite/affine-block-surface'; -export const groupRelationWatcher: SurfaceMiddleware = ( +const groupRelationWatcher: SurfaceMiddleware = ( surface: SurfaceBlockModel ) => { const disposables = [ @@ -26,3 +29,8 @@ export const groupRelationWatcher: SurfaceMiddleware = ( disposables.forEach(d => d.unsubscribe()); }; }; + +export const groupRelationWatcherExtension = surfaceMiddlewareExtension( + 'group-relation-watcher', + groupRelationWatcher +); diff --git a/blocksuite/affine/gfx/group/src/index.ts b/blocksuite/affine/gfx/group/src/index.ts index cf488791de..2b0228cfab 100644 --- a/blocksuite/affine/gfx/group/src/index.ts +++ b/blocksuite/affine/gfx/group/src/index.ts @@ -1,6 +1,6 @@ export * from './adapter'; export * from './command'; export * from './element-renderer'; +export * from './element-view'; export * from './text/text'; export * from './toolbar/config'; -export * from './view'; diff --git a/blocksuite/affine/gfx/group/src/store.ts b/blocksuite/affine/gfx/group/src/store.ts new file mode 100644 index 0000000000..7afbe1c53f --- /dev/null +++ b/blocksuite/affine/gfx/group/src/store.ts @@ -0,0 +1,21 @@ +import { + type StoreExtensionContext, + StoreExtensionProvider, +} from '@blocksuite/affine-ext-loader'; + +import { + groupToMarkdownAdapterMatcher, + groupToPlainTextAdapterMatcher, +} from './adapter'; +import { groupRelationWatcherExtension } from './group-watcher'; + +export class GroupStoreExtension extends StoreExtensionProvider { + override name = 'affine-group-gfx'; + + override setup(context: StoreExtensionContext) { + super.setup(context); + context.register(groupToPlainTextAdapterMatcher); + context.register(groupToMarkdownAdapterMatcher); + context.register(groupRelationWatcherExtension); + } +} diff --git a/blocksuite/affine/gfx/group/src/view.ts b/blocksuite/affine/gfx/group/src/view.ts index 721df9ecf5..e75a09f44c 100644 --- a/blocksuite/affine/gfx/group/src/view.ts +++ b/blocksuite/affine/gfx/group/src/view.ts @@ -1,24 +1,27 @@ -import type { GroupElementModel } from '@blocksuite/affine-model'; -import { GfxElementModelView } from '@blocksuite/std/gfx'; +import { + type ViewExtensionContext, + ViewExtensionProvider, +} from '@blocksuite/affine-ext-loader'; -import { mountGroupTitleEditor } from './text/edgeless-group-title-editor'; +import { effects } from './effects'; +import { GroupElementRendererExtension } from './element-renderer'; +import { GroupElementView } from './element-view'; +import { groupToolbarExtension } from './toolbar/config'; -export class GroupElementView extends GfxElementModelView { - static override type: string = 'group'; +export class GroupViewExtension extends ViewExtensionProvider { + override name = 'affine-group-gfx'; - override onCreated(): void { - super.onCreated(); - - this._initDblClickToEdit(); + override effect(): void { + super.effect(); + effects(); } - private _initDblClickToEdit(): void { - this.on('dblclick', () => { - const edgeless = this.std.view.getBlock(this.std.store.root!.id); - - if (edgeless && !this.model.isLocked()) { - mountGroupTitleEditor(this.model, edgeless); - } - }); + override setup(context: ViewExtensionContext) { + super.setup(context); + context.register(GroupElementRendererExtension); + context.register(GroupElementView); + if (this.isEdgeless(context.scope)) { + context.register(groupToolbarExtension); + } } } diff --git a/blocksuite/affine/gfx/group/tsconfig.json b/blocksuite/affine/gfx/group/tsconfig.json index 1cd15403e9..cfca82fae5 100644 --- a/blocksuite/affine/gfx/group/tsconfig.json +++ b/blocksuite/affine/gfx/group/tsconfig.json @@ -9,6 +9,7 @@ "references": [ { "path": "../../blocks/surface" }, { "path": "../../components" }, + { "path": "../../ext-loader" }, { "path": "../text" }, { "path": "../../model" }, { "path": "../../rich-text" }, diff --git a/blocksuite/affine/gfx/text/src/view.ts b/blocksuite/affine/gfx/text/src/element-view.ts similarity index 100% rename from blocksuite/affine/gfx/text/src/view.ts rename to blocksuite/affine/gfx/text/src/element-view.ts diff --git a/blocksuite/affine/gfx/text/src/index.ts b/blocksuite/affine/gfx/text/src/index.ts index c64a4f2081..b6588cf3be 100644 --- a/blocksuite/affine/gfx/text/src/index.ts +++ b/blocksuite/affine/gfx/text/src/index.ts @@ -2,6 +2,6 @@ export * from './adapter'; export * from './commands'; export * from './edgeless-text-editor'; export * from './element-renderer'; +export * from './element-view'; export * from './tool'; export * from './toolbar'; -export * from './view'; diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index 155c0486c4..4a7ba4d324 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -530,6 +530,7 @@ export const PackageList = [ workspaceDependencies: [ 'blocksuite/affine/blocks/surface', 'blocksuite/affine/components', + 'blocksuite/affine/ext-loader', 'blocksuite/affine/gfx/text', 'blocksuite/affine/model', 'blocksuite/affine/rich-text', diff --git a/yarn.lock b/yarn.lock index f4f98cf9cd..e058eb91ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3159,6 +3159,7 @@ __metadata: dependencies: "@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-gfx-text": "workspace:*" "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-rich-text": "workspace:*"