mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 21:41:52 +08:00
feat(editor): add edgeless crud extension (#9335)
This commit is contained in:
@@ -2,6 +2,7 @@ import { addAttachments } from '@blocksuite/affine-block-attachment';
|
||||
import { addImages } from '@blocksuite/affine-block-image';
|
||||
import {
|
||||
CanvasElementType,
|
||||
EdgelessCRUDIdentifier,
|
||||
SurfaceGroupLikeModel,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -329,11 +330,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
).serialize();
|
||||
options.style = style;
|
||||
|
||||
const id = this.host.service.addBlock(
|
||||
flavour,
|
||||
options,
|
||||
this.surface.model.id
|
||||
);
|
||||
const id = this.crud.addBlock(flavour, options, this.surface.model.id);
|
||||
|
||||
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:paste',
|
||||
@@ -418,6 +415,10 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
return this.host.surface;
|
||||
}
|
||||
|
||||
private get crud() {
|
||||
return this.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private get toolManager() {
|
||||
return this.host.gfx.tool;
|
||||
}
|
||||
@@ -470,7 +471,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
if (!(await this.host.std.collection.blobSync.get(sourceId as string))) {
|
||||
return null;
|
||||
}
|
||||
const attachmentId = this.host.service.addBlock(
|
||||
const attachmentId = this.crud.addBlock(
|
||||
'affine:attachment',
|
||||
{
|
||||
xywh,
|
||||
@@ -491,7 +492,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
const { xywh, style, url, caption, description, icon, image, title } =
|
||||
bookmark.props;
|
||||
|
||||
const bookmarkId = this.host.service.addBlock(
|
||||
const bookmarkId = this.crud.addBlock(
|
||||
'affine:bookmark',
|
||||
{
|
||||
xywh,
|
||||
@@ -581,10 +582,13 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
|
||||
clipboardData.lockedBySelf = false;
|
||||
|
||||
const id = this.host.service.addElement(
|
||||
const id = this.crud.addElement(
|
||||
clipboardData.type as CanvasElementType,
|
||||
clipboardData
|
||||
);
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:paste',
|
||||
page: 'whiteboard editor',
|
||||
@@ -624,7 +628,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
private _createFigmaEmbedBlock(figmaEmbed: BlockSnapshot) {
|
||||
const { xywh, style, url, caption, title, description } = figmaEmbed.props;
|
||||
|
||||
const embedFigmaId = this.host.service.addBlock(
|
||||
const embedFigmaId = this.crud.addBlock(
|
||||
'affine:embed-figma',
|
||||
{
|
||||
xywh,
|
||||
@@ -654,7 +658,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
});
|
||||
}
|
||||
|
||||
const frameId = this.host.service.addBlock(
|
||||
const frameId = this.crud.addBlock(
|
||||
'affine:frame',
|
||||
{
|
||||
xywh,
|
||||
@@ -687,7 +691,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
assignees,
|
||||
} = githubEmbed.props;
|
||||
|
||||
const embedGithubId = this.host.service.addBlock(
|
||||
const embedGithubId = this.crud.addBlock(
|
||||
'affine:embed-github',
|
||||
{
|
||||
xywh,
|
||||
@@ -714,7 +718,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
private _createHtmlEmbedBlock(htmlEmbed: BlockSnapshot) {
|
||||
const { xywh, style, caption, html, design } = htmlEmbed.props;
|
||||
|
||||
const embedHtmlId = this.host.service.addBlock(
|
||||
const embedHtmlId = this.crud.addBlock(
|
||||
'affine:embed-html',
|
||||
{
|
||||
xywh,
|
||||
@@ -735,7 +739,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
if (!(await this.host.std.collection.blobSync.get(sourceId as string))) {
|
||||
return null;
|
||||
}
|
||||
return this.host.service.addBlock(
|
||||
return this.crud.addBlock(
|
||||
'affine:image',
|
||||
{
|
||||
caption,
|
||||
@@ -760,7 +764,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
description,
|
||||
});
|
||||
|
||||
return this.host.service.addBlock(
|
||||
return this.crud.addBlock(
|
||||
'affine:embed-linked-doc',
|
||||
{
|
||||
xywh,
|
||||
@@ -776,7 +780,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
const { xywh, style, url, caption, videoId, image, title, description } =
|
||||
loomEmbed.props;
|
||||
|
||||
const embedLoomId = this.host.service.addBlock(
|
||||
const embedLoomId = this.crud.addBlock(
|
||||
'affine:embed-loom',
|
||||
{
|
||||
xywh,
|
||||
@@ -820,7 +824,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
syncedDocEmbed.props;
|
||||
const referenceInfo = ReferenceInfoSchema.parse({ pageId, params });
|
||||
|
||||
return this.host.service.addBlock(
|
||||
return this.crud.addBlock(
|
||||
'affine:embed-synced-doc',
|
||||
{
|
||||
xywh,
|
||||
@@ -848,7 +852,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
creatorImage,
|
||||
} = youtubeEmbed.props;
|
||||
|
||||
const embedYoutubeId = this.host.service.addBlock(
|
||||
const embedYoutubeId = this.crud.addBlock(
|
||||
'affine:embed-youtube',
|
||||
{
|
||||
xywh,
|
||||
@@ -1085,7 +1089,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
).serialize(),
|
||||
};
|
||||
|
||||
const noteId = edgeless.service.addBlock(
|
||||
const noteId = this.crud.addBlock(
|
||||
'affine:note',
|
||||
noteProps,
|
||||
this.doc.root!.id
|
||||
@@ -1101,7 +1105,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
|
||||
if (typeof content === 'string') {
|
||||
TextUtils.splitIntoLines(content).forEach((line, idx) => {
|
||||
edgeless.service.addBlock(
|
||||
this.crud.addBlock(
|
||||
'affine:paragraph',
|
||||
{ text: new DocCollection.Y.Text(line) },
|
||||
noteId,
|
||||
@@ -1181,7 +1185,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
sortedElements.forEach(ele => {
|
||||
const newIndex = idxGenerator();
|
||||
|
||||
this.edgeless.service.updateElement(ele.id, {
|
||||
this.crud.updateElement(ele.id, {
|
||||
index: newIndex,
|
||||
});
|
||||
});
|
||||
@@ -1323,6 +1327,8 @@ export class EdgelessClipboardController extends PageClipboard {
|
||||
getNewXYWH(data.xywh)
|
||||
);
|
||||
|
||||
if (!element) continue;
|
||||
|
||||
canvasElements.push(element);
|
||||
allElements.push(element);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
CanvasElementType,
|
||||
CommonUtils,
|
||||
EdgelessCRUDIdentifier,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
FontFamilyIcon,
|
||||
@@ -137,6 +138,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _addFrame() {
|
||||
const bound = this._generateTarget(this.connector)?.nextBound;
|
||||
if (!bound) return;
|
||||
@@ -152,7 +157,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
const { service, surfaceBlockModel } = edgeless;
|
||||
const frameMgr = service.frame;
|
||||
const frameIndex = service.frames.length + 1;
|
||||
const id = service.addBlock(
|
||||
const id = this.crud.addBlock(
|
||||
'affine:frame',
|
||||
{
|
||||
title: new DocCollection.Y.Text(`Frame ${frameIndex}`),
|
||||
@@ -178,7 +183,6 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
|
||||
private _addNote() {
|
||||
const { doc } = this.edgeless;
|
||||
const service = this.edgeless.service;
|
||||
const target = this._getTargetXYWH(
|
||||
DEFAULT_NOTE_WIDTH,
|
||||
DEFAULT_NOTE_OVERLAY_HEIGHT
|
||||
@@ -186,7 +190,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
if (!target) return;
|
||||
|
||||
const { xywh, position } = target;
|
||||
const id = service.addBlock(
|
||||
const id = this.crud.addBlock(
|
||||
'affine:note',
|
||||
{
|
||||
xywh: serializeXYWH(...xywh),
|
||||
@@ -205,7 +209,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
id,
|
||||
position: position as [number, number],
|
||||
};
|
||||
service.updateElement(this.connector.id, {
|
||||
this.crud.updateElement(this.connector.id, {
|
||||
target: { id, position },
|
||||
});
|
||||
this.edgeless.service.selection.set({
|
||||
@@ -223,9 +227,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
const { nextBound, position } = result;
|
||||
const { service } = edgeless;
|
||||
const id = createShapeElement(edgeless, currentSource, targetType);
|
||||
if (!id) return;
|
||||
|
||||
service.updateElement(id, { xywh: nextBound.serialize() });
|
||||
service.updateElement(this.connector.id, {
|
||||
this.crud.updateElement(id, { xywh: nextBound.serialize() });
|
||||
this.crud.updateElement(this.connector.id, {
|
||||
target: { id, position },
|
||||
});
|
||||
|
||||
@@ -260,7 +265,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
const textElement = edgelessService.getElementById(textId);
|
||||
if (!textElement) return;
|
||||
|
||||
edgelessService.updateElement(this.connector.id, {
|
||||
this.crud.updateElement(this.connector.id, {
|
||||
target: { id: textId, position },
|
||||
});
|
||||
if (this.currentSource.group instanceof GroupElementModel) {
|
||||
@@ -273,7 +278,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
});
|
||||
this.edgeless.doc.captureSync();
|
||||
} else {
|
||||
const textId = edgelessService.addElement(CanvasElementType.TEXT, {
|
||||
const textId = this.crud.addElement(CanvasElementType.TEXT, {
|
||||
xywh: bound.serialize(),
|
||||
text: new DocCollection.Y.Text(),
|
||||
textAlign: 'left',
|
||||
@@ -283,10 +288,11 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
|
||||
fontWeight: FontWeight.Regular,
|
||||
fontStyle: FontStyle.Normal,
|
||||
});
|
||||
if (!textId) return;
|
||||
const textElement = edgelessService.getElementById(textId);
|
||||
assertInstanceOf(textElement, TextElementModel);
|
||||
|
||||
edgelessService.updateElement(this.connector.id, {
|
||||
this.crud.updateElement(this.connector.id, {
|
||||
target: { id: textId, position },
|
||||
});
|
||||
if (this.currentSource.group instanceof GroupElementModel) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
CanvasElementType,
|
||||
type ConnectionOverlay,
|
||||
ConnectorPathGenerator,
|
||||
EdgelessCRUDIdentifier,
|
||||
Overlay,
|
||||
OverlayIdentifier,
|
||||
type RoughCanvas,
|
||||
@@ -232,12 +233,17 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
|
||||
return this.std.get(OverlayIdentifier('connection')) as ConnectionOverlay;
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _addConnector(source: Connection, target: Connection) {
|
||||
const { edgeless } = this;
|
||||
const id = edgeless.service.addElement(CanvasElementType.CONNECTOR, {
|
||||
const id = this.crud.addElement(CanvasElementType.CONNECTOR, {
|
||||
source,
|
||||
target,
|
||||
});
|
||||
if (!id) return null;
|
||||
return edgeless.service.getElementById(id) as ConnectorElementModel;
|
||||
}
|
||||
|
||||
@@ -354,6 +360,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
|
||||
const { doc, service } = this.edgeless;
|
||||
const bound = this._computeNextBound(type);
|
||||
const id = createEdgelessElement(this.edgeless, this.current, bound);
|
||||
if (!id) return;
|
||||
if (isShape(this.current)) {
|
||||
const { startPosition, endPosition } = getPosition(type);
|
||||
this._addConnector(
|
||||
|
||||
@@ -281,11 +281,12 @@ export function createEdgelessElement(
|
||||
let element: GfxModel | null = null;
|
||||
|
||||
if (isShape(current)) {
|
||||
id = service.addElement(current.type, {
|
||||
id = service.crud.addElement(current.type, {
|
||||
...current.serialize(),
|
||||
text: new DocCollection.Y.Text(),
|
||||
xywh: bound.serialize(),
|
||||
});
|
||||
if (!id) return null;
|
||||
element = service.getElementById(id);
|
||||
} else {
|
||||
const { doc } = edgeless;
|
||||
@@ -335,11 +336,12 @@ export function createShapeElement(
|
||||
targetType: TARGET_SHAPE_TYPE
|
||||
) {
|
||||
const service = edgeless.service;
|
||||
const id = service.addElement('shape', {
|
||||
const id = service.crud.addElement('shape', {
|
||||
shapeType: getShapeType(targetType),
|
||||
radius: getShapeRadius(targetType),
|
||||
text: new DocCollection.Y.Text(),
|
||||
});
|
||||
if (!id) return null;
|
||||
const element = service.getElementById(id);
|
||||
const group = current.group;
|
||||
if (group instanceof GroupElementModel && element) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { TextUtils } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
EdgelessCRUDIdentifier,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import type { RichText } from '@blocksuite/affine-components/rich-text';
|
||||
import type { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -60,6 +63,10 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
|
||||
}
|
||||
`;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _isComposition = false;
|
||||
|
||||
private _keeping = false;
|
||||
@@ -84,7 +91,7 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
|
||||
!connector.labelXYWH ||
|
||||
labelXYWH.some((p, i) => !almostEqual(p, connector.labelXYWH![i]))
|
||||
) {
|
||||
edgeless.service.updateElement(connector.id, {
|
||||
this.crud.updateElement(connector.id, {
|
||||
labelXYWH,
|
||||
});
|
||||
}
|
||||
@@ -172,13 +179,13 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
|
||||
const len = trimed.length;
|
||||
if (len === 0) {
|
||||
// reset
|
||||
edgeless.service.updateElement(connector.id, {
|
||||
this.crud.updateElement(connector.id, {
|
||||
text: undefined,
|
||||
labelXYWH: undefined,
|
||||
labelOffset: undefined,
|
||||
});
|
||||
} else if (len < text.length) {
|
||||
edgeless.service.updateElement(connector.id, {
|
||||
this.crud.updateElement(connector.id, {
|
||||
// @TODO: trim in Y.Text?
|
||||
text: new DocCollection.Y.Text(trimed),
|
||||
});
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { CommonUtils, TextUtils } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
CommonUtils,
|
||||
EdgelessCRUDIdentifier,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import type { RichText } from '@blocksuite/affine-components/rich-text';
|
||||
import type { ShapeElementModel } from '@blocksuite/affine-model';
|
||||
import { MindmapElementModel, TextResizing } from '@blocksuite/affine-model';
|
||||
@@ -24,6 +28,10 @@ import { getSelectedRect } from '../../utils/query.js';
|
||||
const { toRadian } = CommonUtils;
|
||||
|
||||
export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _keeping = false;
|
||||
|
||||
private _lastXYWH = '';
|
||||
@@ -137,7 +145,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
|
||||
const [modelLeftTopX, modelLeftTopY] =
|
||||
this.edgeless.service.viewport.toModelCoord(leftTopX, leftTopY);
|
||||
|
||||
this.edgeless.service.updateElement(this.element.id, {
|
||||
this.crud.updateElement(this.element.id, {
|
||||
xywh: new Bound(
|
||||
modelLeftTopX,
|
||||
modelLeftTopY,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { CommonUtils, TextUtils } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
CommonUtils,
|
||||
EdgelessCRUDIdentifier,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import type { RichText } from '@blocksuite/affine-components/rich-text';
|
||||
import type { TextElementModel } from '@blocksuite/affine-model';
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -23,6 +27,10 @@ import { getSelectedRect } from '../../utils/query.js';
|
||||
const { toRadian } = CommonUtils;
|
||||
|
||||
export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
static BORDER_WIDTH = 1;
|
||||
|
||||
static PADDING_HORIZONTAL = 10;
|
||||
@@ -137,7 +145,7 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
edgeless.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
xywh: bound.serialize(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { CanvasElementType } from '@blocksuite/affine-block-surface';
|
||||
import { type MindmapStyle, TextElementModel } from '@blocksuite/affine-model';
|
||||
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -78,7 +77,7 @@ export const getMindmapRender =
|
||||
});
|
||||
}
|
||||
|
||||
const mindmapId = edgelessService.addElement('mindmap', {
|
||||
const mindmapId = edgelessService.crud.addElement('mindmap', {
|
||||
style: mindmapStyle,
|
||||
children: root,
|
||||
}) as string;
|
||||
@@ -113,10 +112,10 @@ export const textRender: DraggableTool['render'] = (
|
||||
});
|
||||
id = textId!;
|
||||
} else {
|
||||
id = service.addElement(CanvasElementType.TEXT, {
|
||||
id = service.crud.addElement(CanvasElementType.TEXT, {
|
||||
xywh: new Bound(bound.x, vCenter - h / 2, w, h).serialize(),
|
||||
text: new DocCollection.Y.Text(),
|
||||
});
|
||||
}) as string;
|
||||
|
||||
edgeless.doc.captureSync();
|
||||
const textElement = edgeless.service.getElementById(id);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import type {
|
||||
MindmapElementModel,
|
||||
MindmapStyle,
|
||||
@@ -162,6 +163,10 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
|
||||
return getMindMaps(this.theme);
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _toggleMenu() {
|
||||
if (this.tryDisposePopper()) return;
|
||||
this.setEdgelessTool({ type: 'default' });
|
||||
@@ -176,10 +181,11 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
|
||||
},
|
||||
onImportMindMap: (bound: Bound) => {
|
||||
return importMindmap(bound).then(mindmap => {
|
||||
const id = this.edgeless.service.addElement('mindmap', {
|
||||
const id = this.crud.addElement('mindmap', {
|
||||
children: mindmap,
|
||||
layoutType: mindmap?.layoutType === 'left' ? 1 : 0,
|
||||
});
|
||||
if (!id) return;
|
||||
const element = this.edgeless.service.getElementById(
|
||||
id
|
||||
) as MindmapElementModel;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { generateKeyBetweenV2 } from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
DisposableGroup,
|
||||
@@ -98,6 +99,10 @@ export class EdgelessFrameOrderMenu extends SignalWatcher(
|
||||
}
|
||||
`;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private get _frames() {
|
||||
return this.edgeless.service.frames;
|
||||
}
|
||||
@@ -182,7 +187,7 @@ export class EdgelessFrameOrderMenu extends SignalWatcher(
|
||||
|
||||
const frame = this._frames[index];
|
||||
|
||||
this.edgeless.service.updateElement(frame.id, {
|
||||
this.crud.updateElement(frame.id, {
|
||||
presentationIndex: generateKeyBetweenV2(before, after),
|
||||
});
|
||||
this.edgeless.doc.captureSync();
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { CanvasElementType } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
CanvasElementType,
|
||||
EdgelessCRUDIdentifier,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
ellipseSvg,
|
||||
roundedSvg,
|
||||
@@ -137,6 +140,10 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
|
||||
|
||||
override type = 'shape' as const;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
get shapeShadow() {
|
||||
return this.theme === 'dark'
|
||||
? '0 0 7px rgba(0, 0, 0, .22)'
|
||||
@@ -179,12 +186,12 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
|
||||
onDrop: (el, bound) => {
|
||||
const xywh = bound.serialize();
|
||||
const shape = el.data;
|
||||
const id = this.edgeless.service.addElement(CanvasElementType.SHAPE, {
|
||||
const id = this.crud.addElement(CanvasElementType.SHAPE, {
|
||||
shapeType: getShapeType(shape.name),
|
||||
xywh,
|
||||
radius: getShapeRadius(shape.name),
|
||||
});
|
||||
|
||||
if (!id) return;
|
||||
this.edgeless.std
|
||||
.getOptional(TelemetryProvider)
|
||||
?.track('CanvasElementAdded', {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { CanvasElementType } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
CanvasElementType,
|
||||
EdgelessCRUDIdentifier,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
getShapeRadius,
|
||||
getShapeType,
|
||||
@@ -67,6 +70,10 @@ export class EdgelessShapeToolElement extends WithDisposable(LitElement) {
|
||||
}
|
||||
`;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private readonly _addShape = (coord: Coord, padding: Coord) => {
|
||||
const width = 100;
|
||||
const height = 100;
|
||||
@@ -78,7 +85,7 @@ export class EdgelessShapeToolElement extends WithDisposable(LitElement) {
|
||||
coord.y - edgelessY - height * padding.y * zoom
|
||||
);
|
||||
const xywh = new Bound(modelX, modelY, width, height).serialize();
|
||||
this.edgeless.service.addElement(CanvasElementType.SHAPE, {
|
||||
this.crud.addElement(CanvasElementType.SHAPE, {
|
||||
shapeType: getShapeType(this.shape.name),
|
||||
xywh: xywh,
|
||||
radius: getShapeRadius(this.shape.name),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
EdgelessCRUDIdentifier,
|
||||
type ElementRenderer,
|
||||
elementRenderers,
|
||||
type SurfaceBlockModel,
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
MindmapElementModel,
|
||||
RootBlockSchema,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import { clamp } from '@blocksuite/affine-shared/utils';
|
||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
||||
import type {
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Bound, getCommonBound } from '@blocksuite/global/utils';
|
||||
import { type BlockModel, Slot } from '@blocksuite/store';
|
||||
import { Slot } from '@blocksuite/store';
|
||||
import { effect } from '@preact/signals-core';
|
||||
|
||||
import { getSurfaceBlock } from '../../surface-ref-block/utils.js';
|
||||
@@ -43,7 +43,6 @@ import {
|
||||
replaceIdMiddleware,
|
||||
} from './services/template-middlewares.js';
|
||||
import { FIT_TO_SCREEN_PADDING } from './utils/consts.js';
|
||||
import { getLastPropsKey } from './utils/get-last-props-key.js';
|
||||
import { getCursorMode } from './utils/query.js';
|
||||
import {
|
||||
ZOOM_INITIAL,
|
||||
@@ -85,29 +84,6 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
||||
|
||||
TemplateJob = TemplateJob;
|
||||
|
||||
updateElement = (id: string, props: Record<string, unknown>) => {
|
||||
const element = this._surface.getElementById(id);
|
||||
if (element) {
|
||||
const key = getLastPropsKey(
|
||||
element.type as BlockSuite.EdgelessModelKeys,
|
||||
{ ...element.yMap.toJSON(), ...props }
|
||||
);
|
||||
key && this.std.get(EditPropsStore).recordLastProps(key, props);
|
||||
this._surface.updateElement(id, props);
|
||||
return;
|
||||
}
|
||||
|
||||
const block = this.doc.getBlockById(id);
|
||||
if (block) {
|
||||
const key = getLastPropsKey(
|
||||
block.flavour as BlockSuite.EdgelessModelKeys,
|
||||
{ ...block.yBlock.toJSON(), ...props }
|
||||
);
|
||||
key && this.std.get(EditPropsStore).recordLastProps(key, props);
|
||||
this.doc.updateBlock(block, props);
|
||||
}
|
||||
};
|
||||
|
||||
get blocks(): GfxBlockModel[] {
|
||||
return this.layer.blocks;
|
||||
}
|
||||
@@ -179,6 +155,10 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
||||
return this.viewport.zoom;
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
constructor(std: BlockStdScope, flavourProvider: { flavour: string }) {
|
||||
super(std, flavourProvider);
|
||||
const surface = getSurfaceBlock(this.doc);
|
||||
@@ -216,44 +196,11 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
||||
);
|
||||
}
|
||||
|
||||
addBlock(
|
||||
flavour: string,
|
||||
props: Record<string, unknown>,
|
||||
parent?: string | BlockModel,
|
||||
parentIndex?: number
|
||||
) {
|
||||
const key = getLastPropsKey(flavour as BlockSuite.EdgelessModelKeys, props);
|
||||
if (key) {
|
||||
props = this.std.get(EditPropsStore).applyLastProps(key, props);
|
||||
}
|
||||
|
||||
const nProps = {
|
||||
...props,
|
||||
index: this.generateIndex(),
|
||||
};
|
||||
return this.doc.addBlock(flavour as never, nProps, parent, parentIndex);
|
||||
}
|
||||
|
||||
addElement<T extends Record<string, unknown>>(type: string, props: T) {
|
||||
const key = getLastPropsKey(type as BlockSuite.EdgelessModelKeys, props);
|
||||
if (key) {
|
||||
props = this.std.get(EditPropsStore).applyLastProps(key, props) as T;
|
||||
}
|
||||
|
||||
const nProps = {
|
||||
...props,
|
||||
type,
|
||||
index: props.index ?? this.generateIndex(),
|
||||
};
|
||||
const id = this._surface.addElement(nProps);
|
||||
return id;
|
||||
}
|
||||
|
||||
createGroup(elements: BlockSuite.EdgelessModel[] | string[]) {
|
||||
const groups = this.elements.filter(
|
||||
el => el.type === 'group'
|
||||
) as GroupElementModel[];
|
||||
const groupId = this.addElement('group', {
|
||||
const groupId = this.crud.addElement('group', {
|
||||
children: elements.reduce(
|
||||
(pre, el) => {
|
||||
const id = typeof el === 'string' ? el : el.id;
|
||||
@@ -290,12 +237,15 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
||||
|
||||
if (parent !== null) {
|
||||
selection.selectedElements.forEach(element => {
|
||||
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
parent.removeChild(element);
|
||||
});
|
||||
}
|
||||
|
||||
const groupId = this.createGroup(selection.selectedElements);
|
||||
if (!groupId) {
|
||||
return;
|
||||
}
|
||||
const group = this.surface.getElementById(groupId);
|
||||
|
||||
if (parent !== null && group) {
|
||||
@@ -487,12 +437,12 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
||||
}
|
||||
|
||||
if (parent !== null) {
|
||||
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
parent.removeChild(group);
|
||||
}
|
||||
|
||||
elements.forEach(element => {
|
||||
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
|
||||
group.removeChild(element);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
CommonUtils,
|
||||
EdgelessCRUDIdentifier,
|
||||
Overlay,
|
||||
type SurfaceBlockComponent,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -7,7 +8,6 @@ import type { PointerEventState } from '@blocksuite/block-std';
|
||||
import { BaseTool } from '@blocksuite/block-std/gfx';
|
||||
import { Bound, type IVec } from '@blocksuite/global/utils';
|
||||
|
||||
import { deleteElementsV2 } from '../utils/crud.js';
|
||||
import { isTopLevelBlock } from '../utils/query.js';
|
||||
|
||||
const { getSvgPathFromStroke, getStroke, linePolygonIntersects } = CommonUtils;
|
||||
@@ -99,7 +99,9 @@ export class EraserTool extends BaseTool {
|
||||
}
|
||||
|
||||
override dragEnd(_: PointerEventState): void {
|
||||
deleteElementsV2(this.gfx, Array.from(this._eraseTargets));
|
||||
this.gfx.std
|
||||
.get(EdgelessCRUDIdentifier)
|
||||
.deleteElements(Array.from(this._eraseTargets));
|
||||
this._reset();
|
||||
this.doc.captureSync();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { getLastPropsKey } from '@blocksuite/affine-block-surface';
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
type SurfaceMiddleware,
|
||||
SurfaceMiddlewareBuilder,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
|
||||
import { getLastPropsKey } from '../utils/get-last-props-key.js';
|
||||
|
||||
export class EditPropsMiddlewareBuilder extends SurfaceMiddlewareBuilder {
|
||||
static override key = 'editProps';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { focusTextModel } from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
DEFAULT_NOTE_HEIGHT,
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
} from '@blocksuite/global/utils';
|
||||
|
||||
import { DEFAULT_NOTE_OFFSET_X, DEFAULT_NOTE_OFFSET_Y } from './consts.js';
|
||||
import { addBlock } from './crud.js';
|
||||
|
||||
export function addNoteAtPoint(
|
||||
std: BlockStdScope,
|
||||
@@ -37,6 +37,7 @@ export function addNoteAtPoint(
|
||||
} = {}
|
||||
) {
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
const crud = std.get(EdgelessCRUDIdentifier);
|
||||
const {
|
||||
width = DEFAULT_NOTE_WIDTH,
|
||||
height = DEFAULT_NOTE_HEIGHT,
|
||||
@@ -47,8 +48,7 @@ export function addNoteAtPoint(
|
||||
scale = 1,
|
||||
} = options;
|
||||
const [x, y] = gfx.viewport.toModelCoord(point.x, point.y);
|
||||
const blockId = addBlock(
|
||||
std,
|
||||
const blockId = crud.addBlock(
|
||||
'affine:note',
|
||||
{
|
||||
xywh: serializeXYWH(
|
||||
@@ -63,7 +63,7 @@ export function addNoteAtPoint(
|
||||
noteIndex
|
||||
);
|
||||
|
||||
gfx.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:draw',
|
||||
page: 'whiteboard editor',
|
||||
module: 'toolbar',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
|
||||
import type { EdgelessRootService } from '../edgeless-root-service.js';
|
||||
|
||||
/**
|
||||
@@ -12,14 +14,15 @@ export function moveConnectors(
|
||||
service: EdgelessRootService
|
||||
) {
|
||||
const connectors = service.surface.getConnectors(originId);
|
||||
const crud = service.std.get(EdgelessCRUDIdentifier);
|
||||
connectors.forEach(connector => {
|
||||
if (connector.source.id === originId) {
|
||||
service.updateElement(connector.id, {
|
||||
crud.updateElement(connector.id, {
|
||||
source: { ...connector.source, id: targetId },
|
||||
});
|
||||
}
|
||||
if (connector.target.id === originId) {
|
||||
service.updateElement(connector.id, {
|
||||
crud.updateElement(connector.id, {
|
||||
target: { ...connector.target, id: targetId },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
||||
import {
|
||||
type GfxController,
|
||||
GfxControllerIdentifier,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { Connectable } from '../../../_common/utils/index.js';
|
||||
import type { EdgelessRootBlockComponent } from '../index.js';
|
||||
import { getLastPropsKey } from './get-last-props-key.js';
|
||||
import { isConnectable, isNoteBlock } from './query.js';
|
||||
|
||||
/**
|
||||
@@ -42,51 +32,3 @@ export function deleteElements(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteElementsV2(
|
||||
gfx: GfxController,
|
||||
elements: BlockSuite.EdgelessModel[]
|
||||
) {
|
||||
const set = new Set(elements);
|
||||
|
||||
elements.forEach(element => {
|
||||
if (isConnectable(element)) {
|
||||
const connectors = (gfx.surface as SurfaceBlockModel).getConnectors(
|
||||
element.id
|
||||
);
|
||||
connectors.forEach(connector => set.add(connector));
|
||||
}
|
||||
});
|
||||
|
||||
set.forEach(element => {
|
||||
if (isNoteBlock(element)) {
|
||||
const children = gfx.doc.root?.children ?? [];
|
||||
if (children.length > 1) {
|
||||
gfx.doc.deleteBlock(element);
|
||||
}
|
||||
} else {
|
||||
gfx.deleteElement(element.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function addBlock(
|
||||
std: BlockStdScope,
|
||||
flavour: BlockSuite.EdgelessModelKeys,
|
||||
props: Record<string, unknown>,
|
||||
parentId?: string | BlockModel,
|
||||
parentIndex?: number
|
||||
) {
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
const key = getLastPropsKey(flavour as BlockSuite.EdgelessModelKeys, props);
|
||||
if (key) {
|
||||
props = std.get(EditPropsStore).applyLastProps(key, props);
|
||||
}
|
||||
|
||||
const nProps = {
|
||||
...props,
|
||||
index: gfx.layer.generateIndex(),
|
||||
};
|
||||
|
||||
return std.doc.addBlock(flavour as never, nProps, parentId, parentIndex);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { getShapeName, type ShapeProps } from '@blocksuite/affine-model';
|
||||
import type {
|
||||
LastProps,
|
||||
LastPropsKey,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { NodePropsSchema } from '@blocksuite/affine-shared/utils';
|
||||
|
||||
const LastPropsSchema = NodePropsSchema;
|
||||
|
||||
export function getLastPropsKey(
|
||||
modelType: BlockSuite.EdgelessModelKeys,
|
||||
modelProps: Partial<LastProps[LastPropsKey]>
|
||||
): LastPropsKey | null {
|
||||
if (modelType === 'shape') {
|
||||
const { shapeType, radius } = modelProps as ShapeProps;
|
||||
const shapeName = getShapeName(shapeType, radius);
|
||||
return `${modelType}:${shapeName}`;
|
||||
}
|
||||
|
||||
if (isLastPropsKey(modelType)) {
|
||||
return modelType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function isLastPropsKey(key: string): key is LastPropsKey {
|
||||
return Object.keys(LastPropsSchema.shape).includes(key);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
CanvasElementType,
|
||||
EdgelessCRUDIdentifier,
|
||||
type IModelCoord,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -12,11 +13,7 @@ import { ShapeElementModel, TextElementModel } from '@blocksuite/affine-model';
|
||||
import type { PointerEventState } from '@blocksuite/block-std';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import type { IVec } from '@blocksuite/global/utils';
|
||||
import {
|
||||
assertExists,
|
||||
assertInstanceOf,
|
||||
Bound,
|
||||
} from '@blocksuite/global/utils';
|
||||
import { assertInstanceOf, Bound } from '@blocksuite/global/utils';
|
||||
import { DocCollection } from '@blocksuite/store';
|
||||
|
||||
import { EdgelessConnectorLabelEditor } from '../components/text/edgeless-connector-label-editor.js';
|
||||
@@ -77,7 +74,9 @@ export function mountShapeTextEditor(
|
||||
|
||||
if (!shapeElement.text) {
|
||||
const text = new DocCollection.Y.Text();
|
||||
edgeless.service.updateElement(shapeElement.id, { text });
|
||||
edgeless.std
|
||||
.get(EdgelessCRUDIdentifier)
|
||||
.updateElement(shapeElement.id, { text });
|
||||
}
|
||||
|
||||
const updatedElement = edgeless.service.getElementById(shapeElement.id);
|
||||
@@ -164,13 +163,16 @@ export function addText(
|
||||
event.x,
|
||||
event.y
|
||||
);
|
||||
const id = edgeless.service.addElement(CanvasElementType.TEXT, {
|
||||
xywh: new Bound(modelX, modelY, 32, 32).serialize(),
|
||||
text: new DocCollection.Y.Text(),
|
||||
});
|
||||
const id = edgeless.std
|
||||
.get(EdgelessCRUDIdentifier)
|
||||
.addElement(CanvasElementType.TEXT, {
|
||||
xywh: new Bound(modelX, modelY, 32, 32).serialize(),
|
||||
text: new DocCollection.Y.Text(),
|
||||
});
|
||||
if (!id) return;
|
||||
edgeless.doc.captureSync();
|
||||
const textElement = edgeless.service.getElementById(id);
|
||||
assertExists(textElement);
|
||||
if (!textElement) return;
|
||||
if (textElement instanceof TextElementModel) {
|
||||
mountTextElementEditor(textElement, edgeless);
|
||||
}
|
||||
@@ -203,7 +205,7 @@ export function mountConnectorLabelEditor(
|
||||
labelXYWH = bounds.toXYWH();
|
||||
}
|
||||
|
||||
edgeless.service.updateElement(connector.id, {
|
||||
edgeless.std.get(EdgelessCRUDIdentifier).updateElement(connector.id, {
|
||||
text,
|
||||
labelXYWH,
|
||||
labelOffset: { ...labelOffset },
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { updateXYWH } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
EdgelessCRUDIdentifier,
|
||||
updateXYWH,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
AlignBottomIcon,
|
||||
AlignDistributeHorizontallyIcon,
|
||||
@@ -267,7 +270,7 @@ export class EdgelessAlignButton extends WithDisposable(LitElement) {
|
||||
}
|
||||
|
||||
private _updateXYWH(ele: BlockSuite.EdgelessModel, bound: Bound) {
|
||||
const { updateElement } = this.edgeless.service;
|
||||
const { updateElement } = this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
const { updateBlock } = this.edgeless.doc;
|
||||
updateXYWH(ele, bound, updateElement, updateBlock);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import type {
|
||||
BrushElementModel,
|
||||
BrushProps,
|
||||
@@ -57,10 +58,7 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) {
|
||||
pickColor = (event: PickColorEvent) => {
|
||||
if (event.type === 'pick') {
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(
|
||||
ele.id,
|
||||
packColor('color', { ...event.detail })
|
||||
)
|
||||
this.crud.updateElement(ele.id, packColor('color', { ...event.detail }))
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -93,6 +91,10 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) {
|
||||
return this.edgeless.surface;
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private _setBrushProp<K extends keyof BrushProps>(
|
||||
key: K,
|
||||
value: BrushProps[K]
|
||||
@@ -101,7 +103,7 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) {
|
||||
this.elements
|
||||
.filter(notEqual(key, value))
|
||||
.forEach(element =>
|
||||
this.service.updateElement(element.id, { [key]: value })
|
||||
this.crud.updateElement(element.id, { [key]: value })
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
AddTextIcon,
|
||||
ConnectorCWithArrowIcon,
|
||||
@@ -222,10 +223,14 @@ const MODE_CHOOSE: [ConnectorMode, () => TemplateResult<1>][] = [
|
||||
] as const;
|
||||
|
||||
export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) {
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
pickColor = (event: PickColorEvent) => {
|
||||
if (event.type === 'pick') {
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(
|
||||
this.crud.updateElement(
|
||||
ele.id,
|
||||
packColor('stroke', { ...event.detail })
|
||||
)
|
||||
@@ -257,7 +262,7 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) {
|
||||
if (frontEndpointStyle === rearEndpointStyle) return;
|
||||
|
||||
this.elements.forEach(element =>
|
||||
this.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
frontEndpointStyle: rearEndpointStyle,
|
||||
rearEndpointStyle: frontEndpointStyle,
|
||||
})
|
||||
@@ -286,7 +291,7 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) {
|
||||
: 'rearEndpointStyle']: style,
|
||||
};
|
||||
this.elements.forEach(element =>
|
||||
this.service.updateElement(element.id, { ...props })
|
||||
this.crud.updateElement(element.id, { ...props })
|
||||
);
|
||||
}
|
||||
|
||||
@@ -297,7 +302,7 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) {
|
||||
this.elements
|
||||
.filter(notEqual(key, value))
|
||||
.forEach(element =>
|
||||
this.service.updateElement(element.id, { [key]: value })
|
||||
this.crud.updateElement(element.id, { [key]: value })
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
getDocContentWithMaxLength,
|
||||
getEmbedCardIcons,
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
CaptionIcon,
|
||||
CenterPeekIcon,
|
||||
@@ -114,6 +115,10 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
}
|
||||
`;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private readonly _convertToCardView = () => {
|
||||
if (this._isCardView) {
|
||||
return;
|
||||
@@ -146,7 +151,7 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
bound.w = EMBED_CARD_WIDTH[targetStyle];
|
||||
bound.h = EMBED_CARD_HEIGHT[targetStyle];
|
||||
|
||||
const newId = this.edgeless.service.addBlock(
|
||||
const newId = this.crud.addBlock(
|
||||
targetFlavour,
|
||||
{ url, xywh: bound.serialize(), style: targetStyle, caption },
|
||||
this.edgeless.surface.model
|
||||
@@ -197,7 +202,7 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
bound.w = EMBED_CARD_WIDTH[targetStyle];
|
||||
bound.h = EMBED_CARD_HEIGHT[targetStyle];
|
||||
|
||||
const newId = this.edgeless.service.addBlock(
|
||||
const newId = this.crud.addBlock(
|
||||
flavour,
|
||||
{
|
||||
url,
|
||||
@@ -206,6 +211,7 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) {
|
||||
},
|
||||
this.edgeless.surface.model
|
||||
);
|
||||
if (!newId) return;
|
||||
|
||||
this.std.command.exec('reassociateConnectors', {
|
||||
oldId: id,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
NoteIcon,
|
||||
RenameIcon,
|
||||
@@ -51,10 +52,14 @@ function getMostCommonColor(
|
||||
}
|
||||
|
||||
export class EdgelessChangeFrameButton extends WithDisposable(LitElement) {
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
pickColor = (event: PickColorEvent) => {
|
||||
if (event.type === 'pick') {
|
||||
this.frames.forEach(ele =>
|
||||
this.service.updateElement(
|
||||
this.crud.updateElement(
|
||||
ele.id,
|
||||
packColor('background', { ...event.detail })
|
||||
)
|
||||
@@ -116,7 +121,7 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) {
|
||||
|
||||
private _setFrameBackground(color: string) {
|
||||
this.frames.forEach(frame => {
|
||||
this.service.updateElement(frame.id, { background: color });
|
||||
this.crud.updateElement(frame.id, { background: color });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
ExpandIcon,
|
||||
LineStyleIcon,
|
||||
@@ -78,6 +79,10 @@ function getMostCommonBackground(
|
||||
}
|
||||
|
||||
export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private readonly _setBorderRadius = (borderRadius: number) => {
|
||||
this.notes.forEach(note => {
|
||||
const props = {
|
||||
@@ -88,7 +93,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
},
|
||||
},
|
||||
};
|
||||
this.edgeless.service.updateElement(note.id, props);
|
||||
this.crud.updateElement(note.id, props);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -111,7 +116,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
if (event.type === 'pick') {
|
||||
this.notes.forEach(element => {
|
||||
const props = packColor('background', { ...event.detail });
|
||||
this.edgeless.service.updateElement(element.id, props);
|
||||
this.crud.updateElement(element.id, props);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +147,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
|
||||
private _setBackground(background: string) {
|
||||
this.notes.forEach(element => {
|
||||
this.edgeless.service.updateElement(element.id, { background });
|
||||
this.crud.updateElement(element.id, { background });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -173,7 +178,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.edgeless.service.updateElement(note.id, { displayMode: newMode });
|
||||
this.crud.updateElement(note.id, { displayMode: newMode });
|
||||
|
||||
const noteParent = this.doc.getParent(note);
|
||||
assertExists(noteParent);
|
||||
@@ -208,7 +213,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
},
|
||||
},
|
||||
};
|
||||
this.edgeless.service.updateElement(note.id, props);
|
||||
this.crud.updateElement(note.id, props);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -222,7 +227,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
},
|
||||
},
|
||||
};
|
||||
this.edgeless.service.updateElement(note.id, props);
|
||||
this.crud.updateElement(note.id, props);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -236,7 +241,7 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) {
|
||||
},
|
||||
},
|
||||
};
|
||||
this.edgeless.service.updateElement(note.id, props);
|
||||
this.crud.updateElement(note.id, props);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
AddTextIcon,
|
||||
ChangeShapeIcon,
|
||||
@@ -155,6 +156,10 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
|
||||
return this.edgeless.service;
|
||||
}
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
#pickColor<K extends keyof Pick<ShapeProps, 'fillColor' | 'strokeColor'>>(
|
||||
key: K
|
||||
) {
|
||||
@@ -166,7 +171,7 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
|
||||
if (key === 'fillColor' && !ele.filled) {
|
||||
Object.assign(props, { filled: true });
|
||||
}
|
||||
this.service.updateElement(ele.id, props);
|
||||
this.crud.updateElement(ele.id, props);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -199,25 +204,25 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
|
||||
const filled = !isTransparent(fillColor);
|
||||
const color = this._getTextColor(fillColor);
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(ele.id, { filled, fillColor, color })
|
||||
this.crud.updateElement(ele.id, { filled, fillColor, color })
|
||||
);
|
||||
}
|
||||
|
||||
private _setShapeStrokeColor(strokeColor: string) {
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(ele.id, { strokeColor })
|
||||
this.crud.updateElement(ele.id, { strokeColor })
|
||||
);
|
||||
}
|
||||
|
||||
private _setShapeStrokeStyle(strokeStyle: StrokeStyle) {
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(ele.id, { strokeStyle })
|
||||
this.crud.updateElement(ele.id, { strokeStyle })
|
||||
);
|
||||
}
|
||||
|
||||
private _setShapeStrokeWidth(strokeWidth: number) {
|
||||
this.elements.forEach(ele =>
|
||||
this.service.updateElement(ele.id, { strokeWidth })
|
||||
this.crud.updateElement(ele.id, { strokeWidth })
|
||||
);
|
||||
}
|
||||
|
||||
@@ -226,7 +231,7 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
|
||||
shapeStyle === ShapeStyle.General ? FontFamily.Inter : FontFamily.Kalam;
|
||||
|
||||
this.elements.forEach(ele => {
|
||||
this.service.updateElement(ele.id, { shapeStyle, fontFamily });
|
||||
this.crud.updateElement(ele.id, { shapeStyle, fontFamily });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -257,7 +262,7 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
|
||||
this._shapePanel.slots.select.on(shapeName => {
|
||||
this.edgeless.doc.captureSync();
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
shapeType: getShapeType(shapeName),
|
||||
radius: getShapeRadius(shapeName),
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import {
|
||||
ConnectorUtils,
|
||||
EdgelessCRUDIdentifier,
|
||||
normalizeShapeBound,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
@@ -176,6 +176,10 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
}
|
||||
`;
|
||||
|
||||
get crud() {
|
||||
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
||||
}
|
||||
|
||||
private readonly _setFontFamily = (fontFamily: FontFamily) => {
|
||||
const currentFontWeight = getMostCommonFontWeight(this.elements);
|
||||
const fontWeight = TextUtils.isFontWeightSupported(
|
||||
@@ -194,7 +198,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
|
||||
const props = { fontFamily, fontWeight, fontStyle };
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
this._updateElementBound(element);
|
||||
});
|
||||
};
|
||||
@@ -202,7 +206,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
private readonly _setFontSize = (fontSize: number) => {
|
||||
const props = { fontSize };
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
this._updateElementBound(element);
|
||||
});
|
||||
};
|
||||
@@ -213,7 +217,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
) => {
|
||||
const props = { fontWeight, fontStyle };
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
this._updateElementBound(element);
|
||||
});
|
||||
};
|
||||
@@ -221,14 +225,14 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
private readonly _setTextAlign = (textAlign: TextAlign) => {
|
||||
const props = { textAlign };
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
});
|
||||
};
|
||||
|
||||
private readonly _setTextColor = ({ detail: color }: ColorEvent) => {
|
||||
const props = { color };
|
||||
this.elements.forEach(element => {
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -257,7 +261,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
},
|
||||
Bound.fromXYWH(element.deserializedXYWH)
|
||||
);
|
||||
this.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
xywh: newBound.serialize(),
|
||||
});
|
||||
} else if (
|
||||
@@ -285,7 +289,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
prevBounds
|
||||
);
|
||||
bounds.center = center;
|
||||
this.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
labelXYWH: bounds.toXYWH(),
|
||||
});
|
||||
} else if (
|
||||
@@ -296,7 +300,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
element,
|
||||
Bound.fromXYWH(element.deserializedXYWH)
|
||||
);
|
||||
this.service.updateElement(element.id, {
|
||||
this.crud.updateElement(element.id, {
|
||||
xywh: newBound.serialize(),
|
||||
});
|
||||
}
|
||||
@@ -307,7 +311,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
|
||||
if (event.type === 'pick') {
|
||||
this.elements.forEach(element => {
|
||||
const props = packColor('color', { ...event.detail });
|
||||
this.service.updateElement(element.id, buildProps(element, props));
|
||||
this.crud.updateElement(element.id, buildProps(element, props));
|
||||
this._updateElementBound(element);
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
promptDocTitle,
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import type { ImageBlockComponent } from '@blocksuite/affine-block-image';
|
||||
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { isPeekable, peek } from '@blocksuite/affine-components/peek';
|
||||
import type { MenuItemGroup } from '@blocksuite/affine-components/toolbar';
|
||||
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -253,8 +254,9 @@ export const conversionsGroup: MenuItemGroup<ElementToolbarMoreMenuContext> = {
|
||||
if (title === null) return;
|
||||
|
||||
const linkedDoc = createLinkedDocFromNote(doc, element, title);
|
||||
const crud = std.get(EdgelessCRUDIdentifier);
|
||||
// insert linked doc card
|
||||
const cardId = service.addBlock(
|
||||
const cardId = crud.addBlock(
|
||||
'affine:embed-synced-doc',
|
||||
{
|
||||
xywh: element.xywh,
|
||||
@@ -300,15 +302,7 @@ export const conversionsGroup: MenuItemGroup<ElementToolbarMoreMenuContext> = {
|
||||
icon: LinkedPageIcon({ width: '20', height: '20' }),
|
||||
label: 'Create linked doc',
|
||||
type: 'create-linked-doc',
|
||||
action: async ({
|
||||
doc,
|
||||
selection,
|
||||
service,
|
||||
surface,
|
||||
edgeless,
|
||||
host,
|
||||
std,
|
||||
}) => {
|
||||
action: async ({ doc, selection, surface, edgeless, host, std }) => {
|
||||
const title = await promptDocTitle(std);
|
||||
if (title === null) return;
|
||||
|
||||
@@ -318,6 +312,7 @@ export const conversionsGroup: MenuItemGroup<ElementToolbarMoreMenuContext> = {
|
||||
elements,
|
||||
title
|
||||
);
|
||||
const crud = std.get(EdgelessCRUDIdentifier);
|
||||
// delete selected elements
|
||||
doc.transact(() => {
|
||||
deleteElements(edgeless, elements);
|
||||
@@ -326,7 +321,7 @@ export const conversionsGroup: MenuItemGroup<ElementToolbarMoreMenuContext> = {
|
||||
const width = 364;
|
||||
const height = 390;
|
||||
const bound = getCommonBoundWithRotation(elements);
|
||||
const cardId = service.addBlock(
|
||||
const cardId = crud.addBlock(
|
||||
'affine:embed-linked-doc',
|
||||
{
|
||||
xywh: `[${bound.center[0] - width / 2}, ${bound.center[1] - height / 2}, ${width}, ${height}]`,
|
||||
|
||||
Reference in New Issue
Block a user