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,202 @@
import type { Point } from '@blocksuite/global/utils';
export function wait(time: number = 0) {
return new Promise(resolve => {
requestAnimationFrame(() => {
setTimeout(resolve, time);
});
});
}
/**
* simulate click event
* @param target
* @param position position relative to the target
*/
export function click(target: HTMLElement, position: { x: number; y: number }) {
const element = target.getBoundingClientRect();
const clientX = element.x + position.x;
const clientY = element.y + position.y;
target.dispatchEvent(
new PointerEvent('pointerdown', {
clientX,
clientY,
bubbles: true,
pointerId: 1,
isPrimary: true,
})
);
target.dispatchEvent(
new PointerEvent('pointerup', {
clientX,
clientY,
bubbles: true,
pointerId: 1,
isPrimary: true,
})
);
target.dispatchEvent(
new MouseEvent('click', {
clientX,
clientY,
bubbles: true,
})
);
}
type PointerOptions = {
isPrimary?: boolean;
pointerId?: number;
pointerType?: string;
};
const defaultPointerOptions: PointerOptions = {
isPrimary: true,
pointerId: 1,
pointerType: 'mouse',
};
/**
* simulate pointerdown event
* @param target
* @param position position relative to the target
*/
export function pointerdown(
target: HTMLElement,
position: { x: number; y: number },
options: PointerOptions = defaultPointerOptions
) {
const element = target.getBoundingClientRect();
const clientX = element.x + position.x;
const clientY = element.y + position.y;
target.dispatchEvent(
new PointerEvent('pointerdown', {
clientX,
clientY,
bubbles: true,
...options,
})
);
}
/**
* simulate pointerup event
* @param target
* @param position position relative to the target
*/
export function pointerup(
target: HTMLElement,
position: { x: number; y: number },
options: PointerOptions = defaultPointerOptions
) {
const element = target.getBoundingClientRect();
const clientX = element.x + position.x;
const clientY = element.y + position.y;
target.dispatchEvent(
new PointerEvent('pointerup', {
clientX,
clientY,
bubbles: true,
...options,
})
);
}
/**
* simulate pointermove event
* @param target
* @param position position relative to the target
*/
export function pointermove(
target: HTMLElement,
position: { x: number; y: number },
options: PointerOptions = defaultPointerOptions
) {
const element = target.getBoundingClientRect();
const clientX = element.x + position.x;
const clientY = element.y + position.y;
target.dispatchEvent(
new PointerEvent('pointermove', {
clientX,
clientY,
bubbles: true,
...options,
})
);
}
export function drag(
target: HTMLElement,
start: { x: number; y: number },
end: { x: number; y: number },
step: number = 5
) {
pointerdown(target, start);
pointermove(target, start);
if (step !== 0) {
const xStep = (end.x - start.x) / step;
const yStep = (end.y - start.y) / step;
for (const [i] of Array.from({ length: step }).entries()) {
pointermove(target, {
x: start.x + xStep * (i + 1),
y: start.y + yStep * (i + 1),
});
}
}
pointermove(target, end);
pointerup(target, end);
}
export function multiTouchDown(target: Element, points: Point[]) {
points.forEach((point, index) => {
pointerdown(target as HTMLElement, point, {
isPrimary: index === 0,
pointerId: index,
pointerType: 'touch',
});
});
}
export function multiTouchMove(
target: Element,
from: Point[],
to: Point[],
step = 5
) {
if (from.length !== to.length) {
throw new Error('from and to should have the same length');
}
if (step !== 0) {
for (const [i] of Array.from({ length: step }).entries()) {
const stepPoints = from.map((point, index) => ({
x: point.x + ((to[index].x - point.x) / step) * (i + 1),
y: point.y + ((to[index].y - point.y) / step) * (i + 1),
}));
from.forEach((_, index) => {
pointermove(target as HTMLElement, stepPoints[index], {
isPrimary: index === 0,
pointerId: index,
pointerType: 'touch',
});
});
}
}
}
export function multiTouchUp(target: Element, points: Point[]) {
points.forEach((point, index) => {
pointerup(target as HTMLElement, point, {
isPrimary: index === 0,
pointerId: index,
pointerType: 'touch',
});
});
}
@@ -0,0 +1,52 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type {
EdgelessRootBlockComponent,
PageRootBlockComponent,
SurfaceBlockComponent,
} from '@blocksuite/blocks';
import type { Doc } from '@blocksuite/store';
import type { AffineEditorContainer } from '../../index.js';
export function getSurface(doc: Doc, editor: AffineEditorContainer) {
const surfaceModel = doc.getBlockByFlavour('affine:surface');
return editor.host!.view.getBlock(
surfaceModel[0]!.id
) as SurfaceBlockComponent;
}
export function getDocRootBlock(
doc: Doc,
editor: AffineEditorContainer,
mode: 'page'
): PageRootBlockComponent;
export function getDocRootBlock(
doc: Doc,
editor: AffineEditorContainer,
mode: 'edgeless'
): EdgelessRootBlockComponent;
export function getDocRootBlock(
doc: Doc,
editor: AffineEditorContainer,
_?: 'edgeless' | 'page'
) {
return editor.host!.view.getBlock(doc.root!.id) as
| EdgelessRootBlockComponent
| PageRootBlockComponent;
}
export function addNote(doc: Doc, props: Record<string, any> = {}) {
const noteId = doc.addBlock(
'affine:note',
{
xywh: '[0, 0, 800, 100]',
...props,
},
doc.root
);
doc.addBlock('affine:paragraph', {}, noteId);
return noteId;
}
@@ -0,0 +1,14 @@
import { replaceIdMiddleware } from '@blocksuite/blocks';
import { type DocCollection, type DocSnapshot, Job } from '@blocksuite/store';
export async function importFromSnapshot(
collection: DocCollection,
snapshot: DocSnapshot
) {
const job = new Job({
collection,
middlewares: [replaceIdMiddleware],
});
return job.snapshotToDoc(snapshot);
}
@@ -0,0 +1,111 @@
import { effects as blocksEffects } from '@blocksuite/blocks/effects';
import type { BlockCollection } from '@blocksuite/store';
import { effects } from '../../effects.js';
blocksEffects();
effects();
import {
CommunityCanvasTextFonts,
type DocMode,
FontConfigExtension,
} from '@blocksuite/blocks';
import { AffineSchemas } from '@blocksuite/blocks/schemas';
import { assertExists } from '@blocksuite/global/utils';
import {
DocCollection,
IdGeneratorType,
Schema,
Text,
} from '@blocksuite/store';
import { AffineEditorContainer } from '../../index.js';
function createCollectionOptions() {
const schema = new Schema();
const room = Math.random().toString(16).slice(2, 8);
schema.register(AffineSchemas);
const idGenerator: IdGeneratorType = IdGeneratorType.AutoIncrement; // works only in single user mode
return {
id: room,
schema,
idGenerator,
defaultFlags: {
enable_synced_doc_block: true,
enable_pie_menu: true,
readonly: {
'doc:home': false,
},
},
};
}
function initCollection(collection: DocCollection) {
const doc = collection.createDoc({ id: 'doc:home' });
doc.load(() => {
const rootId = doc.addBlock('affine:page', {
title: new Text(),
});
doc.addBlock('affine:surface', {}, rootId);
});
doc.resetHistory();
}
async function createEditor(collection: DocCollection, mode: DocMode = 'page') {
const app = document.createElement('div');
const blockCollection = collection.docs.values().next().value as
| BlockCollection
| undefined;
assertExists(blockCollection, 'Need to create a doc first');
const doc = blockCollection.getDoc();
const editor = new AffineEditorContainer();
editor.doc = doc;
editor.mode = mode;
editor.pageSpecs = editor.pageSpecs.concat([
FontConfigExtension(CommunityCanvasTextFonts),
]);
editor.edgelessSpecs = editor.edgelessSpecs.concat([
FontConfigExtension(CommunityCanvasTextFonts),
]);
app.append(editor);
window.editor = editor;
window.doc = doc;
app.style.width = '100%';
app.style.height = '1280px';
document.body.append(app);
await editor.updateComplete;
return app;
}
export async function setupEditor(mode: DocMode = 'page') {
const collection = new DocCollection(createCollectionOptions());
collection.meta.initialize();
window.collection = collection;
initCollection(collection);
const appElement = await createEditor(collection, mode);
return () => {
appElement.remove();
cleanup();
};
}
export function cleanup() {
window.editor.remove();
delete (window as any).collection;
delete (window as any).editor;
delete (window as any).doc;
}