chore: merge blocksuite source code (#9213)

This commit is contained in:
Mirone
2024-12-20 15:38:06 +08:00
committed by GitHub
parent 2c9ef916f4
commit 30200ff86d
2031 changed files with 238888 additions and 229 deletions
@@ -0,0 +1,130 @@
import { DisposableGroup } from '@blocksuite/global/utils';
import { onSurfaceAdded } from '../../utils/gfx.js';
import type { GfxController } from '../controller.js';
import { GfxExtension, GfxExtensionIdentifier } from '../extension.js';
import { GfxBlockElementModel } from '../model/gfx-block-model.js';
import type { GfxModel } from '../model/model.js';
import type { GfxLocalElementModel } from '../model/surface/local-element-model.js';
import type { SurfaceBlockModel } from '../model/surface/surface-model.js';
import {
GfxElementModelView,
GfxElementModelViewExtIdentifier,
} from './view.js';
export class ViewManager extends GfxExtension {
static override key = 'viewManager';
private _disposable = new DisposableGroup();
private _viewCtorMap = new Map<string, typeof GfxElementModelView>();
private _viewMap = new Map<string, GfxElementModelView>();
constructor(gfx: GfxController) {
super(gfx);
}
static override extendGfx(gfx: GfxController): void {
Object.defineProperty(gfx, 'view', {
get() {
return this.std.get(GfxExtensionIdentifier('viewManager'));
},
});
}
get(model: GfxModel | GfxLocalElementModel | string) {
if (typeof model === 'string') {
if (this._viewMap.has(model)) {
return this._viewMap.get(model);
}
return this.std.view.getBlock(model) ?? null;
} else {
if (model instanceof GfxBlockElementModel) {
return this.std.view.getBlock(model.id) ?? null;
} else {
return this._viewMap.get(model.id) ?? null;
}
}
}
override mounted(): void {
this.std.provider
.getAll(GfxElementModelViewExtIdentifier)
.forEach(viewCtor => {
this._viewCtorMap.set(viewCtor.type, viewCtor);
});
const updateViewOnElementChange = (surface: SurfaceBlockModel) => {
this._disposable.add(
surface.elementAdded.on(payload => {
const model = surface.getElementById(payload.id)!;
const View = this._viewCtorMap.get(model.type) ?? GfxElementModelView;
this._viewMap.set(model.id, new View(model, this.gfx));
})
);
this._disposable.add(
surface.elementRemoved.on(elem => {
const view = this._viewMap.get(elem.id);
this._viewMap.delete(elem.id);
view?.onDestroyed();
})
);
this._disposable.add(
surface.localElementAdded.on(model => {
const View = this._viewCtorMap.get(model.type) ?? GfxElementModelView;
this._viewMap.set(model.id, new View(model, this.gfx));
})
);
this._disposable.add(
surface.localElementDeleted.on(model => {
const view = this._viewMap.get(model.id);
this._viewMap.delete(model.id);
view?.onDestroyed();
})
);
surface.localElementModels.forEach(model => {
const View = this._viewCtorMap.get(model.type) ?? GfxElementModelView;
this._viewMap.set(model.id, new View(model, this.gfx));
});
surface.elementModels.forEach(model => {
const View = this._viewCtorMap.get(model.type) ?? GfxElementModelView;
this._viewMap.set(model.id, new View(model, this.gfx));
});
};
if (this.gfx.surface) {
updateViewOnElementChange(this.gfx.surface);
} else {
this._disposable.add(
onSurfaceAdded(this.std.doc, surface => {
if (surface) {
updateViewOnElementChange(surface);
}
})
);
}
}
override unmounted(): void {
this._disposable.dispose();
this._viewMap.forEach(view => view.onDestroyed());
this._viewMap.clear();
}
}
declare module '../controller.js' {
interface GfxController {
readonly view: ViewManager;
}
}
@@ -0,0 +1,181 @@
import { type Container, createIdentifier } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import {
type Bound,
DisposableGroup,
type IVec,
} from '@blocksuite/global/utils';
import type { PointerEventState } from '../../event/index.js';
import type { Extension } from '../../extension/extension.js';
import type { EditorHost } from '../../view/index.js';
import type { GfxController } from '../index.js';
import type { GfxElementGeometry, PointTestOptions } from '../model/base.js';
import type { GfxPrimitiveElementModel } from '../model/surface/element-model.js';
import type { GfxLocalElementModel } from '../model/surface/local-element-model.js';
export type EventsHandlerMap = {
click: PointerEventState;
dblclick: PointerEventState;
pointerdown: PointerEventState;
pointerenter: PointerEventState;
pointerleave: PointerEventState;
pointermove: PointerEventState;
pointerup: PointerEventState;
};
export type SupportedEvent = keyof EventsHandlerMap;
export const GfxElementModelViewExtIdentifier = createIdentifier<
typeof GfxElementModelView
>('GfxElementModelView');
export class GfxElementModelView<
T extends GfxLocalElementModel | GfxPrimitiveElementModel =
| GfxPrimitiveElementModel
| GfxLocalElementModel,
RendererContext = object,
>
implements GfxElementGeometry, Extension
{
static type: string;
private _handlers = new Map<keyof EventsHandlerMap, ((evt: any) => void)[]>();
private _isConnected = true;
protected disposable = new DisposableGroup();
readonly model: T;
get isConnected() {
return this._isConnected;
}
get rotate() {
return this.model.rotate;
}
get surface() {
return this.model.surface;
}
get type() {
return this.model.type;
}
constructor(
model: T,
readonly gfx: GfxController
) {
this.model = model;
this.onCreated();
}
static setup(di: Container): void {
if (!this.type) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'The GfxElementModelView should have a static `type` property.'
);
}
di.addImpl(GfxElementModelViewExtIdentifier(this.type), () => this);
}
containsBound(bounds: Bound): boolean {
return this.model.containsBound(bounds);
}
dispatch<K extends keyof EventsHandlerMap>(
event: K,
evt: EventsHandlerMap[K]
) {
this._handlers.get(event)?.forEach(callback => callback(evt));
}
getLineIntersections(start: IVec, end: IVec) {
return this.model.getLineIntersections(start, end);
}
getNearestPoint(point: IVec) {
return this.model.getNearestPoint(point);
}
getRelativePointLocation(relativePoint: IVec) {
return this.model.getRelativePointLocation(relativePoint);
}
includesPoint(
x: number,
y: number,
_: PointTestOptions,
__: EditorHost
): boolean {
return this.model.includesPoint(x, y, _, __);
}
intersectsBound(bound: Bound): boolean {
return (
this.containsBound(bound) ||
bound.points.some((point, i, points) =>
this.getLineIntersections(point, points[(i + 1) % points.length])
)
);
}
off<K extends keyof EventsHandlerMap>(
event: K,
callback: (evt: EventsHandlerMap[K]) => void
) {
if (!this._handlers.has(event)) {
return;
}
const callbacks = this._handlers.get(event)!;
const index = callbacks.indexOf(callback);
if (index !== -1) {
callbacks.splice(index, 1);
}
}
on<K extends keyof EventsHandlerMap>(
event: K,
callback: (evt: EventsHandlerMap[K]) => void
) {
if (!this._handlers.has(event)) {
this._handlers.set(event, []);
}
this._handlers.get(event)!.push(callback);
return () => this.off(event, callback);
}
once<K extends keyof EventsHandlerMap>(
event: K,
callback: (evt: EventsHandlerMap[K]) => void
) {
const off = this.on(event, evt => {
off();
callback(evt);
});
return off;
}
onCreated() {}
/**
* Called when the view is destroyed.
* Override this method requires calling `super.onDestroyed()`.
*/
onDestroyed() {
this._isConnected = false;
this.disposable.dispose();
this._handlers.clear();
}
render(_: RendererContext) {}
}