diff --git a/blocksuite/affine/all/package.json b/blocksuite/affine/all/package.json
index b0d2956dbb..c4c7c8278e 100644
--- a/blocksuite/affine/all/package.json
+++ b/blocksuite/affine/all/package.json
@@ -33,6 +33,7 @@
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-fragment-frame-panel": "workspace:*",
"@blocksuite/affine-fragment-outline": "workspace:*",
+ "@blocksuite/affine-gfx-connector": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
@@ -116,8 +117,9 @@
"./fragments/frame-panel": "./src/fragments/frame-panel.ts",
"./fragments/outline": "./src/fragments/outline.ts",
"./gfx/text": "./src/gfx/text.ts",
- "./gfx/shape": "./src/gfx/shape/index.ts",
- "./gfx/note": "./src/gfx/note/index.ts",
+ "./gfx/shape": "./src/gfx/shape.ts",
+ "./gfx/note": "./src/gfx/note.ts",
+ "./gfx/connector": "./src/gfx/connector.ts",
"./gfx/turbo-renderer": "./src/gfx/turbo-renderer.ts",
"./components/block-selection": "./src/components/block-selection.ts",
"./components/block-zero-width": "./src/components/block-zero-width.ts",
diff --git a/blocksuite/affine/all/src/gfx/connector.ts b/blocksuite/affine/all/src/gfx/connector.ts
new file mode 100644
index 0000000000..c3a934bb4c
--- /dev/null
+++ b/blocksuite/affine/all/src/gfx/connector.ts
@@ -0,0 +1 @@
+export * from '@blocksuite/affine-gfx-connector';
diff --git a/blocksuite/affine/all/tsconfig.json b/blocksuite/affine/all/tsconfig.json
index 473b609f77..03984338a2 100644
--- a/blocksuite/affine/all/tsconfig.json
+++ b/blocksuite/affine/all/tsconfig.json
@@ -30,6 +30,7 @@
{ "path": "../fragments/fragment-doc-title" },
{ "path": "../fragments/fragment-frame-panel" },
{ "path": "../fragments/fragment-outline" },
+ { "path": "../gfx/connector" },
{ "path": "../gfx/note" },
{ "path": "../gfx/shape" },
{ "path": "../gfx/text" },
diff --git a/blocksuite/affine/blocks/block-root/package.json b/blocksuite/affine/blocks/block-root/package.json
index 3e73f1ff22..ee35918687 100644
--- a/blocksuite/affine/blocks/block-root/package.json
+++ b/blocksuite/affine/blocks/block-root/package.json
@@ -27,6 +27,7 @@
"@blocksuite/affine-block-table": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-fragment-doc-title": "workspace:*",
+ "@blocksuite/affine-gfx-connector": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/tools.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/tools.ts
index a4a18daf09..2460150c98 100644
--- a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/tools.ts
+++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/tools.ts
@@ -1,4 +1,5 @@
import { frameQuickTool } from '@blocksuite/affine-block-frame';
+import { connectorQuickTool } from '@blocksuite/affine-gfx-connector';
import { noteSeniorTool } from '@blocksuite/affine-gfx-note';
import { shapeSeniorTool } from '@blocksuite/affine-gfx-shape';
import {
@@ -18,15 +19,6 @@ const defaultQuickTool = QuickToolExtension('default', ({ block }) => {
};
});
-const connectorQuickTool = QuickToolExtension('connector', ({ block }) => {
- return {
- type: 'connector',
- content: html``,
- };
-});
-
const linkQuickTool = QuickToolExtension('link', ({ block, gfx }) => {
return {
content: html` {
- editor.inlineEditor?.focusEnd();
- })
- .catch(console.error);
-}
diff --git a/blocksuite/affine/blocks/block-root/src/effects.ts b/blocksuite/affine/blocks/block-root/src/effects.ts
index bf350f2a82..f7f045ff3b 100644
--- a/blocksuite/affine/blocks/block-root/src/effects.ts
+++ b/blocksuite/affine/blocks/block-root/src/effects.ts
@@ -1,3 +1,4 @@
+import { effects as gfxConnectorEffects } from '@blocksuite/affine-gfx-connector/effects';
import { effects as gfxNoteEffects } from '@blocksuite/affine-gfx-note/effects';
import { effects as gfxShapeEffects } from '@blocksuite/affine-gfx-shape/effects';
import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects';
@@ -5,18 +6,13 @@ import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widg
import { EdgelessAutoCompletePanel } from './edgeless/components/auto-complete/auto-complete-panel.js';
import { EdgelessAutoComplete } from './edgeless/components/auto-complete/edgeless-auto-complete.js';
-import { EdgelessConnectorHandle } from './edgeless/components/connector/connector-handle.js';
import {
NOTE_SLICER_WIDGET,
NoteSlicer,
} from './edgeless/components/note-slicer/index.js';
import { EdgelessFontFamilyPanel } from './edgeless/components/panel/font-family-panel.js';
import { EdgelessFontWeightAndStylePanel } from './edgeless/components/panel/font-weight-and-style-panel.js';
-import { NoteDisplayModePanel } from './edgeless/components/panel/note-display-mode-panel.js';
-import { EdgelessNoteShadowPanel } from './edgeless/components/panel/note-shadow-panel.js';
import { EdgelessScalePanel } from './edgeless/components/panel/scale-panel.js';
-import { EdgelessShapePanel } from './edgeless/components/panel/shape-panel.js';
-import { EdgelessShapeStylePanel } from './edgeless/components/panel/shape-style-panel.js';
import { EdgelessSizePanel } from './edgeless/components/panel/size-panel.js';
import { StrokeStylePanel } from './edgeless/components/panel/stroke-style-panel.js';
import {
@@ -27,14 +23,11 @@ import {
EDGELESS_SELECTED_RECT_WIDGET,
EdgelessSelectedRectWidget,
} from './edgeless/components/rects/edgeless-selected-rect.js';
-import { EdgelessConnectorLabelEditor } from './edgeless/components/text/edgeless-connector-label-editor.js';
import { EdgelessGroupTitleEditor } from './edgeless/components/text/edgeless-group-title-editor.js';
import { EdgelessBrushMenu } from './edgeless/components/toolbar/brush/brush-menu.js';
import { EdgelessBrushToolButton } from './edgeless/components/toolbar/brush/brush-tool-button.js';
import { EdgelessSlideMenu } from './edgeless/components/toolbar/common/slide-menu.js';
import { ToolbarArrowUpIcon } from './edgeless/components/toolbar/common/toolbar-arrow-up-icon.js';
-import { EdgelessConnectorMenu } from './edgeless/components/toolbar/connector/connector-menu.js';
-import { EdgelessConnectorToolButton } from './edgeless/components/toolbar/connector/connector-tool-button.js';
import { EdgelessDefaultToolButton } from './edgeless/components/toolbar/default/default-tool-button.js';
import { EdgelessEraserToolButton } from './edgeless/components/toolbar/eraser/eraser-tool-button.js';
import { EdgelessLassoToolButton } from './edgeless/components/toolbar/lasso/lasso-tool-button.js';
@@ -114,6 +107,7 @@ function registerGfxEffects() {
gfxCanvasTextEffects();
gfxShapeEffects();
gfxNoteEffects();
+ gfxConnectorEffects();
}
function registerWidgets() {
@@ -137,10 +131,6 @@ function registerWidgets() {
function registerEdgelessToolbarComponents() {
// Tool buttons
customElements.define('edgeless-brush-tool-button', EdgelessBrushToolButton);
- customElements.define(
- 'edgeless-connector-tool-button',
- EdgelessConnectorToolButton
- );
customElements.define(
'edgeless-default-tool-button',
EdgelessDefaultToolButton
@@ -159,7 +149,6 @@ function registerEdgelessToolbarComponents() {
// Menus
customElements.define('edgeless-brush-menu', EdgelessBrushMenu);
- customElements.define('edgeless-connector-menu', EdgelessConnectorMenu);
customElements.define('edgeless-mindmap-menu', EdgelessMindmapMenu);
customElements.define('edgeless-slide-menu', EdgelessSlideMenu);
@@ -172,21 +161,13 @@ function registerEdgelessPanelComponents() {
'edgeless-font-weight-and-style-panel',
EdgelessFontWeightAndStylePanel
);
- customElements.define('edgeless-note-shadow-panel', EdgelessNoteShadowPanel);
customElements.define('edgeless-size-panel', EdgelessSizePanel);
customElements.define('edgeless-scale-panel', EdgelessScalePanel);
customElements.define('edgeless-font-family-panel', EdgelessFontFamilyPanel);
- customElements.define('edgeless-shape-panel', EdgelessShapePanel);
- customElements.define('note-display-mode-panel', NoteDisplayModePanel);
customElements.define('stroke-style-panel', StrokeStylePanel);
- customElements.define('edgeless-shape-style-panel', EdgelessShapeStylePanel);
}
function registerEdgelessEditorComponents() {
- customElements.define(
- 'edgeless-connector-label-editor',
- EdgelessConnectorLabelEditor
- );
customElements.define(
'edgeless-group-title-editor',
EdgelessGroupTitleEditor
@@ -236,9 +217,6 @@ function registerMiscComponents() {
// Mindmap components
customElements.define('mindmap-import-placeholder', MindMapPlaceholder);
-
- // Connector components
- customElements.define('edgeless-connector-handle', EdgelessConnectorHandle);
}
declare global {
@@ -247,28 +225,20 @@ declare global {
'affine-edgeless-root-preview': EdgelessRootPreviewBlockComponent;
'edgeless-auto-complete-panel': EdgelessAutoCompletePanel;
'edgeless-auto-complete': EdgelessAutoComplete;
- 'edgeless-connector-handle': EdgelessConnectorHandle;
'note-slicer': NoteSlicer;
'edgeless-font-family-panel': EdgelessFontFamilyPanel;
'edgeless-font-weight-and-style-panel': EdgelessFontWeightAndStylePanel;
- 'note-display-mode-panel': NoteDisplayModePanel;
- 'edgeless-note-shadow-panel': EdgelessNoteShadowPanel;
'edgeless-scale-panel': EdgelessScalePanel;
- 'edgeless-shape-panel': EdgelessShapePanel;
- 'edgeless-shape-style-panel': EdgelessShapeStylePanel;
'edgeless-size-panel': EdgelessSizePanel;
'stroke-style-panel': StrokeStylePanel;
'edgeless-navigator-black-background': EdgelessNavigatorBlackBackgroundWidget;
'edgeless-dragging-area-rect': EdgelessDraggingAreaRectWidget;
'edgeless-selected-rect': EdgelessSelectedRectWidget;
- 'edgeless-connector-label-editor': EdgelessConnectorLabelEditor;
'edgeless-group-title-editor': EdgelessGroupTitleEditor;
'edgeless-brush-menu': EdgelessBrushMenu;
'edgeless-brush-tool-button': EdgelessBrushToolButton;
'edgeless-slide-menu': EdgelessSlideMenu;
'toolbar-arrow-up-icon': ToolbarArrowUpIcon;
- 'edgeless-connector-menu': EdgelessConnectorMenu;
- 'edgeless-connector-tool-button': EdgelessConnectorToolButton;
'edgeless-default-tool-button': EdgelessDefaultToolButton;
'edgeless-eraser-tool-button': EdgelessEraserToolButton;
'edgeless-lasso-tool-button': EdgelessLassoToolButton;
diff --git a/blocksuite/affine/blocks/block-root/tsconfig.json b/blocksuite/affine/blocks/block-root/tsconfig.json
index dae0a4db75..c7945fe85d 100644
--- a/blocksuite/affine/blocks/block-root/tsconfig.json
+++ b/blocksuite/affine/blocks/block-root/tsconfig.json
@@ -24,6 +24,7 @@
{ "path": "../block-table" },
{ "path": "../../components" },
{ "path": "../../fragments/fragment-doc-title" },
+ { "path": "../../gfx/connector" },
{ "path": "../../gfx/note" },
{ "path": "../../gfx/shape" },
{ "path": "../../gfx/text" },
diff --git a/blocksuite/affine/gfx/connector/package.json b/blocksuite/affine/gfx/connector/package.json
new file mode 100644
index 0000000000..011260d4ba
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@blocksuite/affine-gfx-connector",
+ "description": "Gfx connector for BlockSuite.",
+ "type": "module",
+ "scripts": {
+ "build": "tsc"
+ },
+ "sideEffects": false,
+ "keywords": [],
+ "author": "toeverything",
+ "license": "MIT",
+ "dependencies": {
+ "@blocksuite/affine-block-surface": "workspace:*",
+ "@blocksuite/affine-components": "workspace:*",
+ "@blocksuite/affine-model": "workspace:*",
+ "@blocksuite/affine-rich-text": "workspace:*",
+ "@blocksuite/affine-shared": "workspace:*",
+ "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
+ "@blocksuite/block-std": "workspace:*",
+ "@blocksuite/global": "workspace:*",
+ "@blocksuite/icons": "^2.2.6",
+ "@blocksuite/store": "workspace:*",
+ "@lit/context": "^1.1.2",
+ "@preact/signals-core": "^1.8.0",
+ "@toeverything/theme": "^1.1.12",
+ "@types/lodash-es": "^4.17.12",
+ "lit": "^3.2.0",
+ "lodash-es": "^4.17.21",
+ "minimatch": "^10.0.1",
+ "rxjs": "^7.8.1",
+ "yjs": "^13.6.21",
+ "zod": "^3.23.8"
+ },
+ "exports": {
+ ".": "./src/index.ts",
+ "./effects": "./src/effects.ts"
+ },
+ "files": [
+ "src",
+ "dist",
+ "!src/__tests__",
+ "!dist/__tests__"
+ ],
+ "version": "0.20.0"
+}
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/connector/connector-handle.ts b/blocksuite/affine/gfx/connector/src/components/connector-handle.ts
similarity index 86%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/connector/connector-handle.ts
rename to blocksuite/affine/gfx/connector/src/components/connector-handle.ts
index 2e31bbe373..d9f967c928 100644
--- a/blocksuite/affine/blocks/block-root/src/edgeless/components/connector/connector-handle.ts
+++ b/blocksuite/affine/gfx/connector/src/components/connector-handle.ts
@@ -1,9 +1,11 @@
import {
type ConnectionOverlay,
+ EdgelessLegacySlotIdentifier,
OverlayIdentifier,
} from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model';
import {
+ type BlockComponent,
type BlockStdScope,
docContext,
stdContext,
@@ -18,8 +20,6 @@ import { css, html, LitElement } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
-import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js';
-
const SIZE = 12;
const HALF_SIZE = SIZE / 2;
@@ -59,15 +59,19 @@ export class EdgelessConnectorHandle extends WithDisposable(LitElement) {
return this.std.get(GfxControllerIdentifier);
}
+ get slots() {
+ return this.std.get(EdgelessLegacySlotIdentifier);
+ }
+
private _bindEvent() {
- const edgeless = this.edgeless;
+ const slots = this.slots;
this._disposables.addFromEvent(this._startHandler, 'pointerdown', e => {
- edgeless.slots.elementResizeStart.next();
+ slots.elementResizeStart.next();
this._capPointerDown(e, 'source');
});
this._disposables.addFromEvent(this._endHandler, 'pointerdown', e => {
- edgeless.slots.elementResizeStart.next();
+ slots.elementResizeStart.next();
this._capPointerDown(e, 'target');
});
this._disposables.add(() => {
@@ -76,11 +80,10 @@ export class EdgelessConnectorHandle extends WithDisposable(LitElement) {
}
private _capPointerDown(e: PointerEvent, connection: 'target' | 'source') {
- const { edgeless, connector, _disposables } = this;
- const { service } = edgeless;
+ const { gfx, connector, slots, _disposables } = this;
e.stopPropagation();
_disposables.addFromEvent(document, 'pointermove', e => {
- const point = service.viewport.toModelCoordFromClientCoord([e.x, e.y]);
+ const point = gfx.viewport.toModelCoordFromClientCoord([e.x, e.y]);
const isStartPointer = connection === 'source';
const otherSideId = connector[isStartPointer ? 'target' : 'source'].id;
@@ -96,16 +99,16 @@ export class EdgelessConnectorHandle extends WithDisposable(LitElement) {
_disposables.dispose();
this._disposables = new DisposableGroup();
this._bindEvent();
- edgeless.slots.elementResizeEnd.next();
+ slots.elementResizeEnd.next();
});
}
override firstUpdated() {
- const { edgeless } = this;
- const { viewport } = edgeless.service;
+ const { gfx } = this;
+ const { viewport } = gfx;
this._lastZoom = viewport.zoom;
- edgeless.service.viewport.viewportUpdated.subscribe(() => {
+ viewport.viewportUpdated.subscribe(() => {
if (viewport.zoom !== this._lastZoom) {
this._lastZoom = viewport.zoom;
this.requestUpdate();
@@ -116,10 +119,10 @@ export class EdgelessConnectorHandle extends WithDisposable(LitElement) {
}
override render() {
- const { service } = this.edgeless;
+ const { gfx } = this;
// path is relative to the element's xywh
const { path } = this.connector;
- const zoom = service.viewport.zoom;
+ const zoom = gfx.viewport.zoom;
const startPoint = Vec.subScalar(Vec.mul(path[0], zoom), HALF_SIZE);
const endPoint = Vec.subScalar(
Vec.mul(path[path.length - 1], zoom),
@@ -155,7 +158,7 @@ export class EdgelessConnectorHandle extends WithDisposable(LitElement) {
accessor doc!: Store;
@property({ attribute: false })
- accessor edgeless!: EdgelessRootBlockComponent;
+ accessor edgeless!: BlockComponent;
@consume({
context: stdContext,
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/gfx-tool/connector-tool.ts b/blocksuite/affine/gfx/connector/src/connector-tool.ts
similarity index 97%
rename from blocksuite/affine/blocks/block-root/src/edgeless/gfx-tool/connector-tool.ts
rename to blocksuite/affine/gfx/connector/src/connector-tool.ts
index 9e1b5d2b92..c9a8c1b64d 100644
--- a/blocksuite/affine/blocks/block-root/src/edgeless/gfx-tool/connector-tool.ts
+++ b/blocksuite/affine/gfx/connector/src/connector-tool.ts
@@ -101,6 +101,7 @@ export class ConnectorTool extends BaseTool {
this._allowCancel = true;
}
+ // @ts-expect-error FIXME: resolve after gfx tool refactor
this.gfx.tool.setTool('default');
this.gfx.selection.set({ elements: [focusedId] });
}
@@ -128,6 +129,7 @@ export class ConnectorTool extends BaseTool {
const connector = this._connector;
this.doc.captureSync();
+ // @ts-expect-error FIXME: resolve after gfx tool refactor
this.gfx.tool.setTool('default');
this.gfx.selection.set({ elements: [connector.id] });
}
diff --git a/blocksuite/affine/gfx/connector/src/effects.ts b/blocksuite/affine/gfx/connector/src/effects.ts
new file mode 100644
index 0000000000..08620298c8
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/src/effects.ts
@@ -0,0 +1,26 @@
+import { EdgelessConnectorHandle } from './components/connector-handle';
+import { EdgelessConnectorLabelEditor } from './text/edgeless-connector-label-editor';
+import { EdgelessConnectorMenu } from './toolbar/connector-menu';
+import { EdgelessConnectorToolButton } from './toolbar/connector-tool-button';
+
+export function effects() {
+ customElements.define(
+ 'edgeless-connector-tool-button',
+ EdgelessConnectorToolButton
+ );
+ customElements.define('edgeless-connector-menu', EdgelessConnectorMenu);
+ customElements.define(
+ 'edgeless-connector-label-editor',
+ EdgelessConnectorLabelEditor
+ );
+ customElements.define('edgeless-connector-handle', EdgelessConnectorHandle);
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'edgeless-connector-tool-button': EdgelessConnectorToolButton;
+ 'edgeless-connector-menu': EdgelessConnectorMenu;
+ 'edgeless-connector-label-editor': EdgelessConnectorLabelEditor;
+ 'edgeless-connector-handle': EdgelessConnectorHandle;
+ }
+}
diff --git a/blocksuite/affine/gfx/connector/src/index.ts b/blocksuite/affine/gfx/connector/src/index.ts
new file mode 100644
index 0000000000..9462c92593
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/src/index.ts
@@ -0,0 +1,4 @@
+export * from './connector-tool';
+export * from './text';
+export * from './toolbar/config';
+export * from './toolbar/quick-tool';
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts b/blocksuite/affine/gfx/connector/src/text/edgeless-connector-label-editor.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts
rename to blocksuite/affine/gfx/connector/src/text/edgeless-connector-label-editor.ts
diff --git a/blocksuite/affine/gfx/connector/src/text/index.ts b/blocksuite/affine/gfx/connector/src/text/index.ts
new file mode 100644
index 0000000000..9a89020a79
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/src/text/index.ts
@@ -0,0 +1 @@
+export * from './text.js';
diff --git a/blocksuite/affine/gfx/connector/src/text/text.ts b/blocksuite/affine/gfx/connector/src/text/text.ts
new file mode 100644
index 0000000000..9a8c3406af
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/src/text/text.ts
@@ -0,0 +1,65 @@
+import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
+import type { ConnectorElementModel } from '@blocksuite/affine-model';
+import type { BlockComponent } from '@blocksuite/block-std';
+import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
+import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
+import type { IVec } from '@blocksuite/global/gfx';
+import { Bound } from '@blocksuite/global/gfx';
+import * as Y from 'yjs';
+
+import { EdgelessConnectorLabelEditor } from './edgeless-connector-label-editor';
+
+export function mountConnectorLabelEditor(
+ connector: ConnectorElementModel,
+ edgeless: BlockComponent,
+ point?: IVec
+) {
+ const mountElm = edgeless.querySelector('.edgeless-mount-point');
+ if (!mountElm) {
+ throw new BlockSuiteError(
+ ErrorCode.ValueNotExists,
+ "edgeless block's mount point does not exist"
+ );
+ }
+
+ const gfx = edgeless.std.get(GfxControllerIdentifier);
+
+ // @ts-expect-error FIXME: resolve after gfx tool refactor
+ gfx.tool.setTool('default');
+ gfx.selection.set({
+ elements: [connector.id],
+ editing: true,
+ });
+
+ if (!connector.text) {
+ const text = new Y.Text();
+ const labelOffset = connector.labelOffset;
+ let labelXYWH = connector.labelXYWH ?? [0, 0, 16, 16];
+
+ if (point) {
+ const center = connector.getNearestPoint(point);
+ const distance = connector.getOffsetDistanceByPoint(center as IVec);
+ const bounds = Bound.fromXYWH(labelXYWH);
+ bounds.center = center;
+ labelOffset.distance = distance;
+ labelXYWH = bounds.toXYWH();
+ }
+
+ edgeless.std.get(EdgelessCRUDIdentifier).updateElement(connector.id, {
+ text,
+ labelXYWH,
+ labelOffset: { ...labelOffset },
+ });
+ }
+
+ const editor = new EdgelessConnectorLabelEditor();
+ editor.connector = connector;
+ editor.edgeless = edgeless;
+
+ mountElm.append(editor);
+ editor.updateComplete
+ .then(() => {
+ editor.inlineEditor?.focusEnd();
+ })
+ .catch(console.error);
+}
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts b/blocksuite/affine/gfx/connector/src/toolbar/config.ts
similarity index 99%
rename from blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts
rename to blocksuite/affine/gfx/connector/src/toolbar/config.ts
index 2219fe7870..0c7c58b900 100644
--- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts
+++ b/blocksuite/affine/gfx/connector/src/toolbar/config.ts
@@ -57,7 +57,7 @@ import {
import { html } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
-import { mountConnectorLabelEditor } from '../../utils/text';
+import { mountConnectorLabelEditor } from '../text';
const FRONT_ENDPOINT_STYLE_LIST = [
{
@@ -123,7 +123,7 @@ const CONNECTOR_MODE_LIST = [
},
] as const satisfies MenuItem[];
-export const builtinConnectorToolbarConfig = {
+export const connectorToolbarConfig = {
actions: [
{
id: 'a.stroke-color',
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-dense-menu.ts b/blocksuite/affine/gfx/connector/src/toolbar/connector-dense-menu.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-dense-menu.ts
rename to blocksuite/affine/gfx/connector/src/toolbar/connector-dense-menu.ts
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-menu.ts b/blocksuite/affine/gfx/connector/src/toolbar/connector-menu.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-menu.ts
rename to blocksuite/affine/gfx/connector/src/toolbar/connector-menu.ts
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-tool-button.ts b/blocksuite/affine/gfx/connector/src/toolbar/connector-tool-button.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/connector/connector-tool-button.ts
rename to blocksuite/affine/gfx/connector/src/toolbar/connector-tool-button.ts
diff --git a/blocksuite/affine/gfx/connector/src/toolbar/quick-tool.ts b/blocksuite/affine/gfx/connector/src/toolbar/quick-tool.ts
new file mode 100644
index 0000000000..0c0d4d8a33
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/src/toolbar/quick-tool.ts
@@ -0,0 +1,14 @@
+import { QuickToolExtension } from '@blocksuite/affine-widget-edgeless-toolbar';
+import { html } from 'lit';
+
+export const connectorQuickTool = QuickToolExtension(
+ 'connector',
+ ({ block }) => {
+ return {
+ type: 'connector',
+ content: html``,
+ };
+ }
+);
diff --git a/blocksuite/affine/gfx/connector/tsconfig.json b/blocksuite/affine/gfx/connector/tsconfig.json
new file mode 100644
index 0000000000..5b280fe89a
--- /dev/null
+++ b/blocksuite/affine/gfx/connector/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./dist",
+ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
+ },
+ "include": ["./src"],
+ "references": [
+ { "path": "../../blocks/block-surface" },
+ { "path": "../../components" },
+ { "path": "../../model" },
+ { "path": "../../rich-text" },
+ { "path": "../../shared" },
+ { "path": "../../widgets/widget-edgeless-toolbar" },
+ { "path": "../../../framework/block-std" },
+ { "path": "../../../framework/global" },
+ { "path": "../../../framework/store" }
+ ]
+}
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/icons.ts b/blocksuite/affine/gfx/note/src/components/icons.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/panel/icons.ts
rename to blocksuite/affine/gfx/note/src/components/icons.ts
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/note-display-mode-panel.ts b/blocksuite/affine/gfx/note/src/components/note-display-mode-panel.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/panel/note-display-mode-panel.ts
rename to blocksuite/affine/gfx/note/src/components/note-display-mode-panel.ts
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/note-shadow-panel.ts b/blocksuite/affine/gfx/note/src/components/note-shadow-panel.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/panel/note-shadow-panel.ts
rename to blocksuite/affine/gfx/note/src/components/note-shadow-panel.ts
diff --git a/blocksuite/affine/gfx/note/src/effects.ts b/blocksuite/affine/gfx/note/src/effects.ts
index f96e3f3222..edd95bf081 100644
--- a/blocksuite/affine/gfx/note/src/effects.ts
+++ b/blocksuite/affine/gfx/note/src/effects.ts
@@ -1,3 +1,5 @@
+import { NoteDisplayModePanel } from './components/note-display-mode-panel';
+import { EdgelessNoteShadowPanel } from './components/note-shadow-panel';
import { EdgelessNoteMenu } from './toolbar/note-menu';
import { EdgelessNoteSeniorButton } from './toolbar/note-senior-button';
import { EdgelessNoteToolButton } from './toolbar/note-tool-button';
@@ -9,6 +11,8 @@ export function effects() {
'edgeless-note-senior-button',
EdgelessNoteSeniorButton
);
+ customElements.define('edgeless-note-shadow-panel', EdgelessNoteShadowPanel);
+ customElements.define('note-display-mode-panel', NoteDisplayModePanel);
}
declare global {
@@ -16,5 +20,7 @@ declare global {
'edgeless-note-tool-button': EdgelessNoteToolButton;
'edgeless-note-menu': EdgelessNoteMenu;
'edgeless-note-senior-button': EdgelessNoteSeniorButton;
+ 'edgeless-note-shadow-panel': EdgelessNoteShadowPanel;
+ 'note-display-mode-panel': NoteDisplayModePanel;
}
}
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/shape-panel.ts b/blocksuite/affine/gfx/shape/src/components/shape-panel.ts
similarity index 93%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/panel/shape-panel.ts
rename to blocksuite/affine/gfx/shape/src/components/shape-panel.ts
index dcd3438e31..e18ef8578a 100644
--- a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/shape-panel.ts
+++ b/blocksuite/affine/gfx/shape/src/components/shape-panel.ts
@@ -1,13 +1,12 @@
-import {
- ShapeComponentConfig,
- type ShapeTool,
-} from '@blocksuite/affine-gfx-shape';
import { ShapeStyle } from '@blocksuite/affine-model';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { Subject } from 'rxjs';
+import type { ShapeTool } from '../shape-tool';
+import { ShapeComponentConfig } from '../toolbar/shape-menu-config';
+
export class EdgelessShapePanel extends LitElement {
static override styles = css`
:host {
diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/shape-style-panel.ts b/blocksuite/affine/gfx/shape/src/components/shape-style-panel.ts
similarity index 100%
rename from blocksuite/affine/blocks/block-root/src/edgeless/components/panel/shape-style-panel.ts
rename to blocksuite/affine/gfx/shape/src/components/shape-style-panel.ts
diff --git a/blocksuite/affine/gfx/shape/src/effects.ts b/blocksuite/affine/gfx/shape/src/effects.ts
index 0397f2051e..d38282b8a0 100644
--- a/blocksuite/affine/gfx/shape/src/effects.ts
+++ b/blocksuite/affine/gfx/shape/src/effects.ts
@@ -1,3 +1,5 @@
+import { EdgelessShapePanel } from './components/shape-panel';
+import { EdgelessShapeStylePanel } from './components/shape-style-panel';
import {
EdgelessShapeMenu,
EdgelessShapeToolButton,
@@ -18,6 +20,8 @@ export function effects() {
'edgeless-toolbar-shape-draggable',
EdgelessToolbarShapeDraggable
);
+ customElements.define('edgeless-shape-panel', EdgelessShapePanel);
+ customElements.define('edgeless-shape-style-panel', EdgelessShapeStylePanel);
}
declare global {
@@ -27,5 +31,7 @@ declare global {
'edgeless-shape-tool-element': EdgelessShapeToolElement;
'edgeless-toolbar-shape-draggable': EdgelessToolbarShapeDraggable;
'edgeless-shape-tool-button': EdgelessShapeToolButton;
+ 'edgeless-shape-panel': EdgelessShapePanel;
+ 'edgeless-shape-style-panel': EdgelessShapeStylePanel;
}
}
diff --git a/tests/blocksuite/e2e/utils/declare-test-window.ts b/tests/blocksuite/e2e/utils/declare-test-window.ts
index 08f534cf06..07e0cb5307 100644
--- a/tests/blocksuite/e2e/utils/declare-test-window.ts
+++ b/tests/blocksuite/e2e/utils/declare-test-window.ts
@@ -1,9 +1,14 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import type * as Effects from '@blocksuite/affine/effects';
+import type * as ConnectorToolEffect from '@blocksuite/affine/gfx/connector';
+import type * as ShapeToolEffect from '@blocksuite/affine/gfx/shape';
import type { Store, Transformer, Workspace } from '@blocksuite/affine/store';
import type { TestAffineEditorContainer } from '@blocksuite/integration-test';
-declare const _GLOBAL_: typeof Effects;
+declare const _GLOBAL_:
+ | typeof Effects
+ | typeof ConnectorToolEffect
+ | typeof ShapeToolEffect;
declare global {
interface Window {
diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts
index 5d6838a793..f2aa524f45 100644
--- a/tools/utils/src/workspace.gen.ts
+++ b/tools/utils/src/workspace.gen.ts
@@ -28,6 +28,7 @@ export const PackageList = [
'blocksuite/affine/fragments/fragment-doc-title',
'blocksuite/affine/fragments/fragment-frame-panel',
'blocksuite/affine/fragments/fragment-outline',
+ 'blocksuite/affine/gfx/connector',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
@@ -308,6 +309,7 @@ export const PackageList = [
'blocksuite/affine/blocks/block-table',
'blocksuite/affine/components',
'blocksuite/affine/fragments/fragment-doc-title',
+ 'blocksuite/affine/gfx/connector',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
@@ -443,6 +445,21 @@ export const PackageList = [
'blocksuite/framework/store',
],
},
+ {
+ location: 'blocksuite/affine/gfx/connector',
+ name: '@blocksuite/affine-gfx-connector',
+ workspaceDependencies: [
+ 'blocksuite/affine/blocks/block-surface',
+ 'blocksuite/affine/components',
+ 'blocksuite/affine/model',
+ 'blocksuite/affine/rich-text',
+ 'blocksuite/affine/shared',
+ 'blocksuite/affine/widgets/widget-edgeless-toolbar',
+ 'blocksuite/framework/block-std',
+ 'blocksuite/framework/global',
+ 'blocksuite/framework/store',
+ ],
+ },
{
location: 'blocksuite/affine/gfx/note',
name: '@blocksuite/affine-gfx-note',
@@ -1075,6 +1092,7 @@ export type PackageName =
| '@blocksuite/affine-fragment-doc-title'
| '@blocksuite/affine-fragment-frame-panel'
| '@blocksuite/affine-fragment-outline'
+ | '@blocksuite/affine-gfx-connector'
| '@blocksuite/affine-gfx-note'
| '@blocksuite/affine-gfx-shape'
| '@blocksuite/affine-gfx-text'
diff --git a/tsconfig.json b/tsconfig.json
index f876a17756..37d1092c64 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -75,6 +75,7 @@
{ "path": "./blocksuite/affine/fragments/fragment-doc-title" },
{ "path": "./blocksuite/affine/fragments/fragment-frame-panel" },
{ "path": "./blocksuite/affine/fragments/fragment-outline" },
+ { "path": "./blocksuite/affine/gfx/connector" },
{ "path": "./blocksuite/affine/gfx/note" },
{ "path": "./blocksuite/affine/gfx/shape" },
{ "path": "./blocksuite/affine/gfx/text" },
diff --git a/yarn.lock b/yarn.lock
index f81a2cacc5..934e84ee3d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2733,6 +2733,7 @@ __metadata:
"@blocksuite/affine-block-table": "workspace:*"
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-fragment-doc-title": "workspace:*"
+ "@blocksuite/affine-gfx-connector": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"
@@ -2969,6 +2970,33 @@ __metadata:
languageName: unknown
linkType: soft
+"@blocksuite/affine-gfx-connector@workspace:*, @blocksuite/affine-gfx-connector@workspace:blocksuite/affine/gfx/connector":
+ version: 0.0.0-use.local
+ resolution: "@blocksuite/affine-gfx-connector@workspace:blocksuite/affine/gfx/connector"
+ dependencies:
+ "@blocksuite/affine-block-surface": "workspace:*"
+ "@blocksuite/affine-components": "workspace:*"
+ "@blocksuite/affine-model": "workspace:*"
+ "@blocksuite/affine-rich-text": "workspace:*"
+ "@blocksuite/affine-shared": "workspace:*"
+ "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*"
+ "@blocksuite/block-std": "workspace:*"
+ "@blocksuite/global": "workspace:*"
+ "@blocksuite/icons": "npm:^2.2.6"
+ "@blocksuite/store": "workspace:*"
+ "@lit/context": "npm:^1.1.2"
+ "@preact/signals-core": "npm:^1.8.0"
+ "@toeverything/theme": "npm:^1.1.12"
+ "@types/lodash-es": "npm:^4.17.12"
+ lit: "npm:^3.2.0"
+ lodash-es: "npm:^4.17.21"
+ minimatch: "npm:^10.0.1"
+ rxjs: "npm:^7.8.1"
+ yjs: "npm:^13.6.21"
+ zod: "npm:^3.23.8"
+ languageName: unknown
+ linkType: soft
+
"@blocksuite/affine-gfx-note@workspace:*, @blocksuite/affine-gfx-note@workspace:blocksuite/affine/gfx/note":
version: 0.0.0-use.local
resolution: "@blocksuite/affine-gfx-note@workspace:blocksuite/affine/gfx/note"
@@ -3511,6 +3539,7 @@ __metadata:
"@blocksuite/affine-fragment-doc-title": "workspace:*"
"@blocksuite/affine-fragment-frame-panel": "workspace:*"
"@blocksuite/affine-fragment-outline": "workspace:*"
+ "@blocksuite/affine-gfx-connector": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"