mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-11 15:16:28 +08:00
feat(editor): gfx connector package (#11091)
This commit is contained in:
@@ -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';
|
||||
@@ -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"
|
||||
}
|
||||
+18
-15
@@ -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,
|
||||
+2
@@ -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);
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -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 {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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:*"
|
||||
|
||||
Reference in New Issue
Block a user