mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 13:25:12 +00:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import { nothing } from 'lit';
|
||||
|
||||
import type { BlockService } from '../../extension/index.js';
|
||||
import { GfxControllerIdentifier } from '../../gfx/identifiers.js';
|
||||
import type { GfxBlockElementModel } from '../../gfx/index.js';
|
||||
import { BlockComponent } from './block-component.js';
|
||||
|
||||
export function isGfxBlockComponent(
|
||||
element: unknown
|
||||
): element is GfxBlockComponent {
|
||||
return (element as GfxBlockComponent)?.[GfxElementSymbol] === true;
|
||||
}
|
||||
|
||||
export const GfxElementSymbol = Symbol('GfxElement');
|
||||
|
||||
function updateTransform(element: GfxBlockComponent) {
|
||||
element.style.transformOrigin = '0 0';
|
||||
element.style.transform = element.getCSSTransform();
|
||||
}
|
||||
|
||||
function handleGfxConnection(instance: GfxBlockComponent) {
|
||||
instance.style.position = 'absolute';
|
||||
|
||||
instance.disposables.add(
|
||||
instance.gfx.viewport.viewportUpdated.on(() => {
|
||||
updateTransform(instance);
|
||||
})
|
||||
);
|
||||
|
||||
instance.disposables.add(
|
||||
instance.doc.slots.blockUpdated.on(({ type, id }) => {
|
||||
if (id === instance.model.id && type === 'update') {
|
||||
updateTransform(instance);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
updateTransform(instance);
|
||||
}
|
||||
|
||||
export abstract class GfxBlockComponent<
|
||||
Model extends GfxBlockElementModel = GfxBlockElementModel,
|
||||
Service extends BlockService = BlockService,
|
||||
WidgetName extends string = string,
|
||||
> extends BlockComponent<Model, Service, WidgetName> {
|
||||
[GfxElementSymbol] = true;
|
||||
|
||||
get gfx() {
|
||||
return this.std.get(GfxControllerIdentifier);
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
handleGfxConnection(this);
|
||||
}
|
||||
|
||||
getCSSTransform() {
|
||||
const viewport = this.gfx.viewport;
|
||||
const { translateX, translateY, zoom } = viewport;
|
||||
const bound = Bound.deserialize(this.model.xywh);
|
||||
|
||||
const scaledX = bound.x * zoom;
|
||||
const scaledY = bound.y * zoom;
|
||||
const deltaX = scaledX - bound.x;
|
||||
const deltaY = scaledY - bound.y;
|
||||
|
||||
return `translate(${translateX + deltaX}px, ${translateY + deltaY}px) scale(${zoom})`;
|
||||
}
|
||||
|
||||
getRenderingRect() {
|
||||
const { xywh$ } = this.model;
|
||||
|
||||
if (!xywh$) {
|
||||
throw new BlockSuiteError(
|
||||
ErrorCode.GfxBlockElementError,
|
||||
`Error on rendering '${this.model.flavour}': Gfx block's model should have 'xywh' property.`
|
||||
);
|
||||
}
|
||||
|
||||
const [x, y, w, h] = JSON.parse(xywh$.value);
|
||||
|
||||
return { x, y, w, h, zIndex: this.toZIndex() };
|
||||
}
|
||||
|
||||
override renderBlock() {
|
||||
const { x, y, w, h, zIndex } = this.getRenderingRect();
|
||||
|
||||
this.style.left = `${x}px`;
|
||||
this.style.top = `${y}px`;
|
||||
this.style.width = `${w}px`;
|
||||
this.style.height = `${h}px`;
|
||||
this.style.zIndex = zIndex;
|
||||
|
||||
return this.renderGfxBlock();
|
||||
}
|
||||
|
||||
renderGfxBlock(): unknown {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
renderPageContent(): unknown {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
override async scheduleUpdate() {
|
||||
const parent = this.parentElement;
|
||||
|
||||
if (this.hasUpdated || !parent || !('scheduleUpdateChildren' in parent)) {
|
||||
super.scheduleUpdate();
|
||||
} else {
|
||||
await (parent.scheduleUpdateChildren as (id: string) => Promise<void>)(
|
||||
this.model.id
|
||||
);
|
||||
|
||||
super.scheduleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
toZIndex(): string {
|
||||
return this.gfx.layer.getZIndex(this.model).toString() ?? '0';
|
||||
}
|
||||
|
||||
updateZIndex(): void {
|
||||
this.style.zIndex = this.toZIndex();
|
||||
}
|
||||
}
|
||||
|
||||
export function toGfxBlockComponent<
|
||||
Model extends GfxBlockElementModel,
|
||||
Service extends BlockService,
|
||||
WidgetName extends string,
|
||||
B extends typeof BlockComponent<Model, Service, WidgetName>,
|
||||
>(CustomBlock: B) {
|
||||
// @ts-expect-error FIXME: ts error
|
||||
return class extends CustomBlock {
|
||||
[GfxElementSymbol] = true;
|
||||
|
||||
get gfx() {
|
||||
return this.std.get(GfxControllerIdentifier);
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
handleGfxConnection(this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
getCSSTransform() {
|
||||
const viewport = this.gfx.viewport;
|
||||
const { translateX, translateY, zoom } = viewport;
|
||||
const bound = Bound.deserialize(this.model.xywh);
|
||||
|
||||
const scaledX = bound.x * zoom;
|
||||
const scaledY = bound.y * zoom;
|
||||
const deltaX = scaledX - bound.x;
|
||||
const deltaY = scaledY - bound.y;
|
||||
|
||||
return `translate(${translateX + deltaX}px, ${translateY + deltaY}px) scale(${zoom})`;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
getRenderingRect(): {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number | string;
|
||||
h: number | string;
|
||||
zIndex: string;
|
||||
} {
|
||||
const { xywh$ } = this.model;
|
||||
|
||||
if (!xywh$) {
|
||||
throw new BlockSuiteError(
|
||||
ErrorCode.GfxBlockElementError,
|
||||
`Error on rendering '${this.model.flavour}': Gfx block's model should have 'xywh' property.`
|
||||
);
|
||||
}
|
||||
|
||||
const [x, y, w, h] = JSON.parse(xywh$.value);
|
||||
|
||||
return { x, y, w, h, zIndex: this.toZIndex() };
|
||||
}
|
||||
|
||||
override renderBlock() {
|
||||
const { x, y, w, h, zIndex } = this.getRenderingRect();
|
||||
|
||||
this.style.left = `${x}px`;
|
||||
this.style.top = `${y}px`;
|
||||
this.style.width = typeof w === 'number' ? `${w}px` : w;
|
||||
this.style.height = typeof h === 'number' ? `${h}px` : h;
|
||||
this.style.zIndex = zIndex;
|
||||
|
||||
return this.renderGfxBlock();
|
||||
}
|
||||
|
||||
renderGfxBlock(): unknown {
|
||||
return this.renderPageContent();
|
||||
}
|
||||
|
||||
renderPageContent() {
|
||||
return super.renderBlock();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
override async scheduleUpdate() {
|
||||
const parent = this.parentElement;
|
||||
|
||||
if (this.hasUpdated || !parent || !('scheduleUpdateChildren' in parent)) {
|
||||
super.scheduleUpdate();
|
||||
} else {
|
||||
await (parent.scheduleUpdateChildren as (id: string) => Promise<void>)(
|
||||
this.model.id
|
||||
);
|
||||
|
||||
super.scheduleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
toZIndex(): string {
|
||||
return this.gfx.layer.getZIndex(this.model).toString() ?? '0';
|
||||
}
|
||||
|
||||
updateZIndex(): void {
|
||||
this.style.zIndex = this.toZIndex();
|
||||
}
|
||||
} as B & {
|
||||
new (...args: any[]): GfxBlockComponent;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user