Skip to content

Commit

Permalink
refactor(editor): query methods in edgeless api (#9407)
Browse files Browse the repository at this point in the history
  • Loading branch information
Saul-Mirone committed Dec 28, 2024
1 parent dc92d78 commit 1e4b180
Show file tree
Hide file tree
Showing 35 changed files with 296 additions and 275 deletions.
22 changes: 22 additions & 0 deletions blocksuite/affine/block-surface/src/extensions/crud-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,26 @@ export class EdgelessCRUDExtension extends Extension {
this.std.doc.updateBlock(block, props);
}
};

getElementById(id: string): BlockSuite.EdgelessModel | null {
const surface = this._surface;
if (!surface) {
return null;
}
const el =
surface.getElementById(id) ??
(this.std.doc.getBlockById(
id
) as BlockSuite.EdgelessBlockModelType | null);
return el;
}

getElementsByType<K extends keyof BlockSuite.SurfaceElementModelMap>(
type: K
): BlockSuite.SurfaceElementModelMap[K][] {
if (!this._surface) {
return [];
}
return this._surface.getElementsByType(type);
}
}
79 changes: 79 additions & 0 deletions blocksuite/affine/shared/src/utils/edgeless.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { FrameBlockModel, GroupElementModel } from '@blocksuite/affine-model';
import type { GfxBlockElementModel } from '@blocksuite/block-std/gfx';
import {
deserializeXYWH,
getQuadBoundWithRotation,
} from '@blocksuite/global/utils';
import type { BlockModel } from '@blocksuite/store';

export function getSelectedRect(selected: BlockSuite.EdgelessModel[]): DOMRect {
if (selected.length === 0) {
return new DOMRect();
}

const lockedElementsByFrame = selected
.map(selectable => {
if (selectable instanceof FrameBlockModel && selectable.isLocked()) {
return selectable.descendantElements;
}
return [];
})
.flat();

selected = [...new Set([...selected, ...lockedElementsByFrame])];

if (selected.length === 1) {
const [x, y, w, h] = deserializeXYWH(selected[0].xywh);
return new DOMRect(x, y, w, h);
}

return getElementsWithoutGroup(selected).reduce(
(bounds, selectable, index) => {
const rotate = isTopLevelBlock(selectable) ? 0 : selectable.rotate;
const [x, y, w, h] = deserializeXYWH(selectable.xywh);
let { left, top, right, bottom } = getQuadBoundWithRotation({
x,
y,
w,
h,
rotate,
});

if (index !== 0) {
left = Math.min(left, bounds.left);
top = Math.min(top, bounds.top);
right = Math.max(right, bounds.right);
bottom = Math.max(bottom, bounds.bottom);
}

bounds.x = left;
bounds.y = top;
bounds.width = right - left;
bounds.height = bottom - top;

return bounds;
},
new DOMRect()
);
}

export function getElementsWithoutGroup(elements: BlockSuite.EdgelessModel[]) {
const set = new Set<BlockSuite.EdgelessModel>();

elements.forEach(element => {
if (element instanceof GroupElementModel) {
element.descendantElements
.filter(descendant => !(descendant instanceof GroupElementModel))
.forEach(descendant => set.add(descendant));
} else {
set.add(element);
}
});
return Array.from(set);
}

export function isTopLevelBlock(
selectable: BlockModel | BlockSuite.EdgelessModel | null
): selectable is GfxBlockElementModel {
return !!selectable && 'flavour' in selectable;
}
1 change: 1 addition & 0 deletions blocksuite/affine/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './button-popper.js';
export * from './collapsed/index.js';
export * from './dnd/index.js';
export * from './dom/index.js';
export * from './edgeless.js';
export * from './event.js';
export * from './file/index.js';
export * from './insert.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '@blocksuite/affine-shared/services';
import {
isInsidePageEditor,
isTopLevelBlock,
isUrlInClipboard,
matchFlavours,
referenceToNode,
Expand Down Expand Up @@ -83,7 +84,6 @@ import {
isAttachmentBlock,
isCanvasElementWithText,
isImageBlock,
isTopLevelBlock,
} from '../utils/query.js';

const BLOCKSUITE_SURFACE = 'blocksuite/surface';
Expand Down Expand Up @@ -595,9 +595,7 @@ export class EdgelessClipboardController extends PageClipboard {
segment: 'toolbar',
type: clipboardData.type as string,
});
const element = this.host.service.getElementById(
id
) as BlockSuite.SurfaceModel;
const element = this.crud.getElementById(id) as BlockSuite.SurfaceModel;
assertExists(element);
return element;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
surfaceBlockModel
);
edgeless.doc.captureSync();
const frame = service.getElementById(id);
const frame = this.crud.getElementById(id);
if (!frame) return;

this.connector.target = {
Expand Down Expand Up @@ -225,7 +225,6 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {

const currentSource = this.currentSource;
const { nextBound, position } = result;
const { service } = edgeless;
const id = createShapeElement(edgeless, currentSource, targetType);
if (!id) return;

Expand All @@ -235,10 +234,10 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
});

mountShapeTextEditor(
service.getElementById(id) as ShapeElementModel,
this.crud.getElementById(id) as ShapeElementModel,
this.edgeless
);
edgeless.service.selection.set({
this.gfx.selection.set({
elements: [id],
editing: true,
});
Expand All @@ -250,7 +249,6 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
if (!target) return;
const { xywh, position } = target;
const bound = Bound.fromXYWH(xywh);
const edgelessService = this.edgeless.service;

const textFlag = this.edgeless.doc.awarenessStore.getFlag(
'enable_edgeless_text'
Expand All @@ -262,7 +260,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
});
if (!textId) return;

const textElement = edgelessService.getElementById(textId);
const textElement = this.crud.getElementById(textId);
if (!textElement) return;

this.crud.updateElement(this.connector.id, {
Expand All @@ -272,7 +270,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
this.currentSource.group.addChild(textElement);
}

this.edgeless.service.selection.set({
this.gfx.selection.set({
elements: [textId],
editing: false,
});
Expand All @@ -289,7 +287,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
fontStyle: FontStyle.Normal,
});
if (!textId) return;
const textElement = edgelessService.getElementById(textId);
const textElement = this.crud.getElementById(textId);
assertInstanceOf(textElement, TextElementModel);

this.crud.updateElement(this.connector.id, {
Expand All @@ -299,7 +297,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
this.currentSource.group.addChild(textElement);
}

this.edgeless.service.selection.set({
this.gfx.selection.set({
elements: [textId],
editing: false,
});
Expand Down Expand Up @@ -331,7 +329,7 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) {
}

private _connectorExist() {
return !!this.edgeless.service.getElementById(this.connector.id);
return !!this.crud.getElementById(this.connector.id);
}

private _generateTarget(connector: ConnectorElementModel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
private _autoCompleteOverlay!: AutoCompleteOverlay;

private readonly _onPointerDown = (e: PointerEvent, type: Direction) => {
const { service } = this.edgeless;
const viewportRect = service.viewport.boundingClientRect;
const start = service.viewport.toModelCoord(
const viewportRect = this.gfx.viewport.boundingClientRect;
const start = this.gfx.viewport.toModelCoord(
e.clientX - viewportRect.left,
e.clientY - viewportRect.top
);
Expand All @@ -176,7 +175,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
let connector: ConnectorElementModel | null;

this._disposables.addFromEvent(document, 'pointermove', e => {
const point = service.viewport.toModelCoord(
const point = this.gfx.viewport.toModelCoord(
e.clientX - viewportRect.left,
e.clientY - viewportRect.top
);
Expand Down Expand Up @@ -237,14 +236,17 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
return this.std.get(EdgelessCRUDIdentifier);
}

get gfx() {
return this.std.get(GfxControllerIdentifier);
}

private _addConnector(source: Connection, target: Connection) {
const { edgeless } = this;
const id = this.crud.addElement(CanvasElementType.CONNECTOR, {
source,
target,
});
if (!id) return null;
return edgeless.service.getElementById(id) as ConnectorElementModel;
return this.crud.getElementById(id) as ConnectorElementModel;
}

private _addMindmapNode(target: 'sibling' | 'child') {
Expand Down Expand Up @@ -274,7 +276,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {

requestAnimationFrame(() => {
mountShapeTextEditor(
this.edgeless.service.getElementById(newNode) as ShapeElementModel,
this.crud.getElementById(newNode) as ShapeElementModel,
this.edgeless
);
});
Expand Down Expand Up @@ -375,7 +377,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
);

mountShapeTextEditor(
service.getElementById(id) as ShapeElementModel,
this.crud.getElementById(id) as ShapeElementModel,
this.edgeless
);
} else {
Expand Down Expand Up @@ -403,12 +405,12 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
return service.getConnectors(element.id).reduce((prev, current) => {
if (current.target.id === element.id && current.source.id) {
prev.push(
service.getElementById(current.source.id) as ShapeElementModel
this.crud.getElementById(current.source.id) as ShapeElementModel
);
}
if (current.source.id === element.id && current.target.id) {
prev.push(
service.getElementById(current.target.id) as ShapeElementModel
this.crud.getElementById(current.target.id) as ShapeElementModel
);
}

Expand Down Expand Up @@ -467,9 +469,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {

private _initOverlay() {
const { surface } = this.edgeless;
this._autoCompleteOverlay = new AutoCompleteOverlay(
this.std.get(GfxControllerIdentifier)
);
this._autoCompleteOverlay = new AutoCompleteOverlay(this.gfx);
surface.renderer.addOverlay(this._autoCompleteOverlay);
}

Expand Down Expand Up @@ -656,7 +656,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
override connectedCallback(): void {
super.connectedCallback();
this._pathGenerator = new ConnectorPathGenerator({
getElementById: id => this.edgeless.service.getElementById(id),
getElementById: id => this.crud.getElementById(id),
});
this._initOverlay();
}
Expand All @@ -665,7 +665,7 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
const { _disposables, edgeless } = this;

_disposables.add(
this.edgeless.service.selection.slots.updated.on(() => {
this.gfx.selection.slots.updated.on(() => {
this._autoCompleteOverlay.linePoints = [];
this._autoCompleteOverlay.renderShape = null;
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,17 +277,18 @@ export function createEdgelessElement(
) {
let id;
const { service } = edgeless;
const { crud } = service;

let element: GfxModel | null = null;

if (isShape(current)) {
id = service.crud.addElement(current.type, {
id = crud.addElement(current.type, {
...current.serialize(),
text: new DocCollection.Y.Text(),
xywh: bound.serialize(),
});
if (!id) return null;
element = service.getElementById(id);
element = crud.getElementById(id);
} else {
const { doc } = edgeless;
id = doc.addBlock(
Expand Down Expand Up @@ -335,14 +336,14 @@ export function createShapeElement(
current: ShapeElementModel | NoteBlockModel,
targetType: TARGET_SHAPE_TYPE
) {
const service = edgeless.service;
const id = service.crud.addElement('shape', {
const { crud } = edgeless.service;
const id = crud.addElement('shape', {
shapeType: getShapeType(targetType),
radius: getShapeRadius(targetType),
text: new DocCollection.Y.Text(),
});
if (!id) return null;
const element = service.getElementById(id);
const element = crud.getElementById(id);
const group = current.group;
if (group instanceof GroupElementModel && element) {
group.addChild(element);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { EMBED_CARD_HEIGHT } from '@blocksuite/affine-shared/consts';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import {
clamp,
getElementsWithoutGroup,
getSelectedRect,
requestThrottledConnectedFrame,
stopPropagation,
} from '@blocksuite/affine-shared/utils';
Expand Down Expand Up @@ -72,10 +74,8 @@ import {
AI_CHAT_BLOCK_MIN_HEIGHT,
AI_CHAT_BLOCK_MIN_WIDTH,
} from '../../utils/consts.js';
import { getElementsWithoutGroup } from '../../utils/group.js';
import {
getSelectableBounds,
getSelectedRect,
isAIChatBlock,
isAttachmentBlock,
isBookmarkBlock,
Expand Down
Loading

0 comments on commit 1e4b180

Please sign in to comment.