feat(editor): gfx connector package (#11091)

This commit is contained in:
Saul-Mirone
2025-03-22 14:39:05 +00:00
parent d398ee4dfa
commit 1f0fc9d47a
38 changed files with 284 additions and 137 deletions
+4 -2
View File
@@ -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",
@@ -0,0 +1 @@
export * from '@blocksuite/affine-gfx-connector';
+1
View File
@@ -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" },
@@ -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:*",
@@ -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`<edgeless-connector-tool-button
.edgeless=${block}
></edgeless-connector-tool-button>`,
};
});
const linkQuickTool = QuickToolExtension('link', ({ block, gfx }) => {
return {
content: html`<edgeless-link-tool-button
@@ -1,12 +1,12 @@
import { edgelessTextToolbarConfig } from '@blocksuite/affine-block-edgeless-text';
import { frameToolbarExtension } from '@blocksuite/affine-block-frame';
import { connectorToolbarConfig } from '@blocksuite/affine-gfx-connector';
import { textToolbarConfig } from '@blocksuite/affine-gfx-text';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store';
import { builtinBrushToolbarConfig } from './brush';
import { builtinConnectorToolbarConfig } from './connector';
import { builtinGroupToolbarConfig } from './group';
import { builtinMindmapToolbarConfig } from './mindmap';
import { builtinLockedToolbarConfig, builtinMiscToolbarConfig } from './misc';
@@ -27,7 +27,7 @@ export const EdgelessElementToolbarExtension: ExtensionType[] = [
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:connector'),
config: builtinConnectorToolbarConfig,
config: connectorToolbarConfig,
}),
ToolbarModuleExtension({
@@ -4,6 +4,7 @@ import {
PresentTool,
} from '@blocksuite/affine-block-frame';
import { ConnectionOverlay } from '@blocksuite/affine-block-surface';
import { ConnectorTool } from '@blocksuite/affine-gfx-connector';
import { NoteTool } from '@blocksuite/affine-gfx-note';
import { ShapeTool } from '@blocksuite/affine-gfx-shape';
import { TextTool } from '@blocksuite/affine-gfx-text';
@@ -20,7 +21,6 @@ import { MindMapDragExtension } from './element-transform/mind-map-drag.js';
import { SnapExtension } from './element-transform/snap-manager.js';
import { MindMapIndicatorOverlay } from './element-transform/utils/indicator-overlay.js';
import { BrushTool } from './gfx-tool/brush-tool.js';
import { ConnectorTool } from './gfx-tool/connector-tool.js';
import { DefaultTool } from './gfx-tool/default-tool.js';
import { EmptyTool } from './gfx-tool/empty-tool.js';
import { EraserTool } from './gfx-tool/eraser-tool.js';
@@ -2,6 +2,7 @@ import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmar
import { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text';
import { isNoteBlock } from '@blocksuite/affine-block-surface';
import { toast } from '@blocksuite/affine-components/toast';
import { mountConnectorLabelEditor } from '@blocksuite/affine-gfx-connector';
import { mountShapeTextEditor, ShapeTool } from '@blocksuite/affine-gfx-shape';
import {
ConnectorElementModel,
@@ -48,7 +49,6 @@ import {
isSingleMindMapNode,
} from './utils/mindmap.js';
import { isCanvasElement } from './utils/query.js';
import { mountConnectorLabelEditor } from './utils/text.js';
export class EdgelessPageKeyboardManager extends PageKeyboardManager {
get gfx() {
@@ -8,6 +8,7 @@ import {
isNoteBlock,
OverlayIdentifier,
} from '@blocksuite/affine-block-surface';
import { mountConnectorLabelEditor } from '@blocksuite/affine-gfx-connector';
import { mountShapeTextEditor } from '@blocksuite/affine-gfx-shape';
import { addText, mountTextElementEditor } from '@blocksuite/affine-gfx-text';
import type {
@@ -51,10 +52,7 @@ import type { EdgelessRootBlockComponent } from '../index.js';
import { prepareCloneData } from '../utils/clone-utils.js';
import { calPanDelta } from '../utils/panning-utils.js';
import { isCanvasElement, isEdgelessTextBlock } from '../utils/query.js';
import {
mountConnectorLabelEditor,
mountGroupTitleEditor,
} from '../utils/text.js';
import { mountGroupTitleEditor } from '../utils/text.js';
import { DefaultModeDragType } from './default-tool-ext/ext.js';
export class DefaultTool extends BaseTool {
@@ -1,5 +1,4 @@
export { BrushTool } from './brush-tool.js';
export { ConnectorTool, type ConnectorToolOptions } from './connector-tool.js';
export { DefaultTool } from './default-tool.js';
export { EmptyTool } from './empty-tool.js';
export { EraserTool } from './eraser-tool.js';
@@ -1,16 +1,8 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
import type {
ConnectorElementModel,
GroupElementModel,
} from '@blocksuite/affine-model';
import type { GroupElementModel } 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 '../components/text/edgeless-connector-label-editor.js';
import { EdgelessGroupTitleEditor } from '../components/text/edgeless-group-title-editor.js';
export function mountGroupTitleEditor(
@@ -39,57 +31,3 @@ export function mountGroupTitleEditor(
mountElm.append(groupEditor);
}
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);
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);
}
@@ -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;
@@ -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" },
@@ -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"
}
@@ -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,
@@ -101,6 +101,7 @@ export class ConnectorTool extends BaseTool<ConnectorToolOptions> {
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<ConnectorToolOptions> {
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] });
}
@@ -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;
}
}
@@ -0,0 +1,4 @@
export * from './connector-tool';
export * from './text';
export * from './toolbar/config';
export * from './toolbar/quick-tool';
@@ -0,0 +1 @@
export * from './text.js';
@@ -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);
}
@@ -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<ConnectorMode>[];
export const builtinConnectorToolbarConfig = {
export const connectorToolbarConfig = {
actions: [
{
id: 'a.stroke-color',
@@ -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`<edgeless-connector-tool-button
.edgeless=${block}
></edgeless-connector-tool-button>`,
};
}
);
@@ -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" }
]
}
@@ -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;
}
}
@@ -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 {
@@ -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;
}
}
@@ -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 {
+18
View File
@@ -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'
+1
View File
@@ -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" },
+29
View File
@@ -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:*"