mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 10:22:55 +08:00
feat(editor): add edgeless crud extension (#9335)
This commit is contained in:
140
blocksuite/affine/block-surface/src/extensions/crud-extension.ts
Normal file
140
blocksuite/affine/block-surface/src/extensions/crud-extension.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
type BlockStdScope,
|
||||
Extension,
|
||||
StdIdentifier,
|
||||
} from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { SurfaceBlockModel } from '../surface-model';
|
||||
import { getLastPropsKey } from '../utils/get-last-props-key';
|
||||
import { isConnectable, isNoteBlock } from './query';
|
||||
|
||||
export const EdgelessCRUDIdentifier = createIdentifier<EdgelessCRUDExtension>(
|
||||
'AffineEdgelessCrudService'
|
||||
);
|
||||
|
||||
export class EdgelessCRUDExtension extends Extension {
|
||||
constructor(readonly std: BlockStdScope) {
|
||||
super();
|
||||
}
|
||||
|
||||
static override setup(di: Container) {
|
||||
di.add(this, [StdIdentifier]);
|
||||
di.addImpl(EdgelessCRUDIdentifier, provider => provider.get(this));
|
||||
}
|
||||
|
||||
private get _gfx() {
|
||||
return this.std.get(GfxControllerIdentifier);
|
||||
}
|
||||
|
||||
private get _surface() {
|
||||
return this._gfx.surface as SurfaceBlockModel | null;
|
||||
}
|
||||
|
||||
deleteElements(elements: BlockSuite.EdgelessModel[]) {
|
||||
const surface = this._surface;
|
||||
if (!surface) {
|
||||
console.error('surface is not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
const gfx = this.std.get(GfxControllerIdentifier);
|
||||
const set = new Set(elements);
|
||||
elements.forEach(element => {
|
||||
if (isConnectable(element)) {
|
||||
const connectors = surface.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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addBlock(
|
||||
flavour: BlockSuite.EdgelessModelKeys | string,
|
||||
props: Record<string, unknown>,
|
||||
parentId?: string | BlockModel,
|
||||
parentIndex?: number
|
||||
) {
|
||||
const gfx = this.std.get(GfxControllerIdentifier);
|
||||
const key = getLastPropsKey(flavour as BlockSuite.EdgelessModelKeys, props);
|
||||
if (key) {
|
||||
props = this.std.get(EditPropsStore).applyLastProps(key, props);
|
||||
}
|
||||
|
||||
const nProps = {
|
||||
...props,
|
||||
index: gfx.layer.generateIndex(),
|
||||
};
|
||||
|
||||
return this.std.doc.addBlock(
|
||||
flavour as never,
|
||||
nProps,
|
||||
parentId,
|
||||
parentIndex
|
||||
);
|
||||
}
|
||||
|
||||
addElement<T extends Record<string, unknown>>(type: string, props: T) {
|
||||
const surface = this._surface;
|
||||
if (!surface) {
|
||||
console.error('surface is not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
const gfx = this.std.get(GfxControllerIdentifier);
|
||||
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 ?? gfx.layer.generateIndex(),
|
||||
};
|
||||
|
||||
return surface.addElement(nProps);
|
||||
}
|
||||
|
||||
updateElement = (id: string, props: Record<string, unknown>) => {
|
||||
const surface = this._surface;
|
||||
if (!surface) {
|
||||
console.error('surface is not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
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.std.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.std.doc.updateBlock(block, props);
|
||||
}
|
||||
};
|
||||
}
|
||||
1
blocksuite/affine/block-surface/src/extensions/index.ts
Normal file
1
blocksuite/affine/block-surface/src/extensions/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './crud-extension';
|
||||
16
blocksuite/affine/block-surface/src/extensions/query.ts
Normal file
16
blocksuite/affine/block-surface/src/extensions/query.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { NoteBlockModel } from '@blocksuite/affine-model';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { Connectable } from '../managers/connector-manager';
|
||||
|
||||
export function isConnectable(
|
||||
element: BlockSuite.EdgelessModel | null
|
||||
): element is Connectable {
|
||||
return !!element && element.connectable;
|
||||
}
|
||||
|
||||
export function isNoteBlock(
|
||||
element: BlockModel | BlockSuite.EdgelessModel | null
|
||||
): element is NoteBlockModel {
|
||||
return !!element && 'flavour' in element && element.flavour === 'affine:note';
|
||||
}
|
||||
Reference in New Issue
Block a user