refactor(editor): should not rely on doc collection type (#9501)

This commit is contained in:
Saul-Mirone
2025-01-03 06:30:27 +00:00
parent cb5d7eaabc
commit 897c7d4284
55 changed files with 200 additions and 158 deletions

View File

@@ -138,7 +138,6 @@ export class Clipboard extends LifeCycleWatcher {
const payload = {
file: item,
assets: job.assetsManager,
blockVersions: doc.collection.meta.blockVersions,
workspaceId: doc.collection.id,
pageId: doc.id,
};

View File

@@ -7,7 +7,7 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs';
import { COLLECTION_VERSION, PAGE_VERSION } from '../consts.js';
import type { BlockModel, BlockSchemaType, Doc } from '../index.js';
import { DocCollection, IdGeneratorType, Schema } from '../index.js';
import type { DocMeta } from '../store/index.js';
import type { DocMeta } from '../store/workspace.js';
import type { BlockSuiteDoc } from '../yjs/index.js';
import {
NoteBlockSchema,
@@ -432,7 +432,7 @@ describe('addBlock', () => {
);
let called = false;
collection.meta.docMetaUpdated.on(() => {
collection.slots.docListUpdated.on(() => {
called = true;
});

View File

@@ -22,11 +22,16 @@ import {
BlockSuiteDoc,
type RawAwarenessState,
} from '../yjs/index.js';
import { BlockCollection, type GetDocOptions } from './doc/block-collection.js';
import type { Doc, Query } from './doc/index.js';
import { BlockCollection } from './doc/block-collection.js';
import type { Doc } from './doc/index.js';
import type { IdGeneratorType } from './id.js';
import { pickIdGenerator } from './id.js';
import { DocCollectionMeta } from './meta.js';
import type {
CreateDocOptions,
GetDocOptions,
Workspace,
} from './workspace.js';
export type DocCollectionOptions = {
schema: Schema;
@@ -69,7 +74,7 @@ export interface StackItem {
meta: Map<'cursor-location' | 'selection-state', unknown>;
}
export class DocCollection {
export class DocCollection implements Workspace {
protected readonly _schema: Schema;
readonly awarenessStore: AwarenessStore;
@@ -91,7 +96,7 @@ export class DocCollection {
meta: DocCollectionMeta;
slots = {
docUpdated: new Slot(),
docListUpdated: new Slot(),
docRemoved: new Slot<string>(),
docCreated: new Slot<string>(),
};
@@ -161,7 +166,7 @@ export class DocCollection {
this.blockCollections.set(doc.id, doc);
});
this.meta.docMetaUpdated.on(() => this.slots.docUpdated.emit());
this.meta.docMetaUpdated.on(() => this.slots.docListUpdated.emit());
this.meta.docMetaRemoved.on(id => {
const space = this.getBlockCollection(id);
@@ -189,8 +194,8 @@ export class DocCollection {
* If the `init` parameter is passed, a `surface`, `note`, and `paragraph` block
* will be created in the doc simultaneously.
*/
createDoc(options: { id?: string; query?: Query } = {}) {
const { id: docId = this.idGenerator(), query } = options;
createDoc(options: CreateDocOptions = {}) {
const { id: docId = this.idGenerator(), query, readonly } = options;
if (this._hasDoc(docId)) {
throw new BlockSuiteError(
ErrorCode.DocCollectionError,
@@ -205,7 +210,7 @@ export class DocCollection {
tags: [],
});
this.slots.docCreated.emit(docId);
return this.getDoc(docId, { query }) as Doc;
return this.getDoc(docId, { query, readonly }) as Doc;
}
dispose() {

View File

@@ -7,7 +7,7 @@ import { Text } from '../../reactive/text.js';
import type { BlockModel } from '../../schema/base.js';
import type { IdGenerator } from '../../utils/id-generator.js';
import type { AwarenessStore, BlockSuiteDoc } from '../../yjs/index.js';
import type { DocCollection } from '../collection.js';
import type { GetDocOptions, Workspace } from '../workspace.js';
import { Doc } from './doc.js';
import type { YBlock } from './index.js';
import type { Query } from './query.js';
@@ -24,17 +24,12 @@ export type BlockProps = BlockSysProps & Record<string, unknown>;
type DocOptions = {
id: string;
collection: DocCollection;
collection: Workspace;
doc: BlockSuiteDoc;
awarenessStore: AwarenessStore;
idGenerator?: IdGenerator;
};
export type GetDocOptions = {
query?: Query;
readonly?: boolean;
};
export class BlockCollection {
private _awarenessUpdateDisposable: Disposable | null = null;
@@ -42,7 +37,7 @@ export class BlockCollection {
private readonly _canUndo$ = signal(false);
private readonly _collection: DocCollection;
private readonly _collection: Workspace;
private readonly _docMap = {
undefined: new Map<string, Doc>(),
@@ -145,11 +140,6 @@ export class BlockCollection {
>(),
};
// So, we apply a listener at the top level for the flat structure of the current
get awarenessSync() {
return this.collection.awarenessSync;
}
get blobSync() {
return this.collection.blobSync;
}

View File

@@ -4,3 +4,4 @@ export type * from './doc/block-collection.js';
export * from './doc/index.js';
export * from './id.js';
export type * from './meta.js';
export * from './workspace.js';

View File

@@ -4,26 +4,12 @@ import type * as Y from 'yjs';
import { COLLECTION_VERSION, PAGE_VERSION } from '../consts.js';
import type { BlockSuiteDoc } from '../yjs/index.js';
import type { DocCollection } from './collection.js';
import type {
DocMeta,
DocsPropertiesMeta,
WorkspaceMeta,
} from './workspace.js';
// please use `declare module '@blocksuite/store'` to extend this interface
export interface DocMeta {
id: string;
title: string;
tags: string[];
createDate: number;
updatedDate?: number;
}
export type Tag = {
id: string;
value: string;
color: string;
};
export type DocsPropertiesMeta = {
tags?: {
options: Tag[];
};
};
export type DocCollectionMetaState = {
pages?: unknown[];
properties?: DocsPropertiesMeta;
@@ -34,7 +20,7 @@ export type DocCollectionMetaState = {
avatar?: string;
};
export class DocCollectionMeta {
export class DocCollectionMeta implements WorkspaceMeta {
private readonly _handleDocCollectionMetaEvents = (
events: Y.YEvent<Y.Array<unknown> | Y.Text | Y.Map<unknown>>[]
) => {

View File

@@ -0,0 +1,86 @@
import type { Slot } from '@blocksuite/global/utils';
import type { BlobEngine, DocEngine } from '@blocksuite/sync';
import type { Schema } from '../schema/schema.js';
import type { IdGenerator } from '../utils/id-generator.js';
import type { AwarenessStore } from '../yjs/awareness.js';
import type { BlockSuiteDoc } from '../yjs/doc.js';
import type { Doc } from './doc/doc.js';
import type { BlockCollection } from './doc/index.js';
import type { Query } from './doc/query.js';
export type Tag = {
id: string;
value: string;
color: string;
};
export type DocsPropertiesMeta = {
tags?: {
options: Tag[];
};
};
export interface DocMeta {
id: string;
title: string;
tags: string[];
createDate: number;
updatedDate?: number;
favorite?: boolean;
}
export type GetDocOptions = {
query?: Query;
readonly?: boolean;
};
export type CreateDocOptions = GetDocOptions & {
id?: string;
};
export interface WorkspaceMeta {
get docMetas(): DocMeta[];
getDocMeta(id: string): DocMeta | undefined;
setDocMeta(id: string, props: Partial<DocMeta>): void;
removeDocMeta(id: string): void;
get properties(): DocsPropertiesMeta;
setProperties(meta: DocsPropertiesMeta): void;
get avatar(): string | undefined;
setAvatar(avatar: string): void;
get name(): string | undefined;
setName(name: string): void;
commonFieldsUpdated: Slot;
hasVersion: boolean;
writeVersion(workspace: Workspace): void;
get docs(): unknown[] | undefined;
initialize(): void;
}
export interface Workspace {
readonly id: string;
readonly meta: WorkspaceMeta;
readonly idGenerator: IdGenerator;
readonly docSync: DocEngine;
readonly blobSync: BlobEngine;
readonly awarenessStore: AwarenessStore;
get schema(): Schema;
get doc(): BlockSuiteDoc;
get docs(): Map<string, BlockCollection>;
slots: {
docListUpdated: Slot;
docCreated: Slot<string>;
docRemoved: Slot<string>;
};
createDoc(options?: CreateDocOptions): Doc;
getDoc(docId: string, options?: GetDocOptions): Doc | null;
removeDoc(docId: string): void;
dispose(): void;
}

View File

@@ -1,7 +1,7 @@
import { z } from 'zod';
import type { Doc } from '../store/doc/doc.js';
import type { DocMeta, DocsPropertiesMeta } from '../store/meta.js';
import type { DocMeta, DocsPropertiesMeta } from '../store/workspace.js';
export type BlockSnapshot = {
type: 'block';