feat(editor): add editor store (#9584)

This commit is contained in:
Saul-Mirone
2025-01-08 07:47:43 +00:00
parent 0554df6bc2
commit fe727412be
25 changed files with 203 additions and 67 deletions

View File

@@ -0,0 +1,17 @@
import type { Container } from '@blocksuite/global/di';
/**
* Generic extension.
* Extensions are used to set up the dependency injection container.
* In most cases, you won't need to use this class directly.
* We provide helper classes like `CommandExtension` and `BlockViewExtension` to make it easier to create extensions.
*/
export abstract class Extension {
static setup(_di: Container): void {
// do nothing
}
}
export interface ExtensionType {
setup(di: Container): void;
}

View File

@@ -1,17 +1,2 @@
import type { Container } from '@blocksuite/global/di';
/**
* Generic extension.
* Extensions are used to set up the dependency injection container.
* In most cases, you won't need to use this class directly.
* We provide helper classes like `CommandExtension` and `BlockViewExtension` to make it easier to create extensions.
*/
export abstract class Extension {
static setup(_di: Container): void {
// do nothing
}
}
export interface ExtensionType {
setup(di: Container): void;
}
export * from './extension';
export * from './store-extension';

View File

@@ -0,0 +1,41 @@
import { type Container, createIdentifier } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { StoreIdentifier } from '../store/identifier';
import type { Store } from '../store/store';
import { Extension } from './extension';
export const StoreExtensionIdentifier =
createIdentifier<StoreExtension>('StoreExtension');
export const storeExtensionSymbol = Symbol('StoreExtension');
export class StoreExtension extends Extension {
constructor(readonly store: Store) {
super();
}
static readonly [storeExtensionSymbol] = true;
static override setup(di: Container) {
if (!this.key) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'Key is not defined in the StoreExtension'
);
}
di.add(this, [StoreIdentifier]);
di.addImpl(StoreExtensionIdentifier(this.key), provider =>
provider.get(this)
);
}
static readonly key: string;
}
export function isStoreExtensionConstructor(
extension: object
): extension is typeof StoreExtension {
return storeExtensionSymbol in extension;
}

View File

@@ -6,6 +6,7 @@ export * from './extension';
export * from './model';
export * from './reactive';
export * from './schema';
export * from './store';
export * from './transformer';
export { type IdGenerator, nanoid, uuidv4 } from './utils/id-generator';
export * from './yjs';

View File

@@ -0,0 +1,5 @@
import { createIdentifier } from '@blocksuite/global/di';
import type { Store } from './store';
export const StoreIdentifier = createIdentifier<Store>('Store');

View File

@@ -0,0 +1,2 @@
export * from './identifier';
export * from './store';

View File

@@ -0,0 +1,41 @@
import { Container, type ServiceProvider } from '@blocksuite/global/di';
import type { Extension, StoreExtension } from '../extension';
import type { Blocks } from '../model';
import { StoreIdentifier } from './identifier';
export interface StoreOptions {
blocks: Blocks;
provider?: ServiceProvider;
extensions?: (typeof Extension | typeof StoreExtension)[];
}
export class Store {
private readonly _blocks: Blocks;
private readonly _provider: ServiceProvider;
get blocks() {
return this._blocks;
}
get provider() {
return this._provider;
}
get awareness() {
return this._blocks.awarenessStore;
}
constructor(options: StoreOptions) {
this._blocks = options.blocks;
const container = new Container();
container.addImpl(StoreIdentifier, () => this);
const userExtensions = options.extensions ?? [];
userExtensions.forEach(extension => {
extension.setup(container);
});
this._provider = container.provider(undefined, options.provider);
}
}