feat(editor): add editor store (#9584)
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
type DraftModel,
|
type DraftModel,
|
||||||
type Query,
|
type Query,
|
||||||
Slice,
|
Slice,
|
||||||
|
Store,
|
||||||
Text,
|
Text,
|
||||||
} from '@blocksuite/store';
|
} from '@blocksuite/store';
|
||||||
import { render, type TemplateResult } from 'lit';
|
import { render, type TemplateResult } from 'lit';
|
||||||
@@ -197,8 +198,9 @@ async function renderNoteContent(
|
|||||||
};
|
};
|
||||||
const previewDoc = doc.doc.getBlocks({ query });
|
const previewDoc = doc.doc.getBlocks({ query });
|
||||||
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
||||||
|
const store = new Store({ blocks: previewDoc });
|
||||||
const previewStd = new BlockStdScope({
|
const previewStd = new BlockStdScope({
|
||||||
doc: previewDoc,
|
store,
|
||||||
extensions: previewSpec.value,
|
extensions: previewSpec.value,
|
||||||
});
|
});
|
||||||
const previewTemplate = previewStd.render();
|
const previewTemplate = previewStd.render();
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ import {
|
|||||||
ThemeProvider,
|
ThemeProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { BlockSelection, BlockStdScope } from '@blocksuite/block-std';
|
import { BlockSelection, BlockStdScope } from '@blocksuite/block-std';
|
||||||
import { assertExists, Bound } from '@blocksuite/global/utils';
|
import { Bound } from '@blocksuite/global/utils';
|
||||||
import { html } from 'lit';
|
import { Store } from '@blocksuite/store';
|
||||||
|
import { html, nothing } from 'lit';
|
||||||
import { choose } from 'lit/directives/choose.js';
|
import { choose } from 'lit/directives/choose.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import { guard } from 'lit/directives/guard.js';
|
import { guard } from 'lit/directives/guard.js';
|
||||||
@@ -25,7 +26,12 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
|||||||
protected override _renderSyncedView = () => {
|
protected override _renderSyncedView = () => {
|
||||||
const { syncedDoc, editorMode } = this;
|
const { syncedDoc, editorMode } = this;
|
||||||
|
|
||||||
assertExists(syncedDoc, 'Doc should exist');
|
if (!syncedDoc) {
|
||||||
|
console.error('Synced doc is not found');
|
||||||
|
return html`${nothing}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = new Store({ blocks: syncedDoc });
|
||||||
|
|
||||||
let containerStyleMap = styleMap({
|
let containerStyleMap = styleMap({
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -64,7 +70,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
|||||||
() => html`
|
() => html`
|
||||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: syncedDoc,
|
store,
|
||||||
extensions: this._buildPreviewSpec('page:preview'),
|
extensions: this._buildPreviewSpec('page:preview'),
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
@@ -75,7 +81,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
|||||||
() => html`
|
() => html`
|
||||||
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: syncedDoc,
|
store,
|
||||||
extensions: this._buildPreviewSpec('edgeless:preview'),
|
extensions: this._buildPreviewSpec('edgeless:preview'),
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,9 +26,14 @@ import {
|
|||||||
} from '@blocksuite/block-std';
|
} from '@blocksuite/block-std';
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||||
import { assertExists, Bound, getCommonBound } from '@blocksuite/global/utils';
|
import { assertExists, Bound, getCommonBound } from '@blocksuite/global/utils';
|
||||||
import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store';
|
import {
|
||||||
|
type GetBlocksOptions,
|
||||||
|
type Query,
|
||||||
|
Store,
|
||||||
|
Text,
|
||||||
|
} from '@blocksuite/store';
|
||||||
import { computed } from '@preact/signals-core';
|
import { computed } from '@preact/signals-core';
|
||||||
import { html, type PropertyValues } from 'lit';
|
import { html, nothing, type PropertyValues } from 'lit';
|
||||||
import { query, state } from 'lit/decorators.js';
|
import { query, state } from 'lit/decorators.js';
|
||||||
import { choose } from 'lit/directives/choose.js';
|
import { choose } from 'lit/directives/choose.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
@@ -146,7 +151,12 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
|||||||
const editorMode = this.editorMode;
|
const editorMode = this.editorMode;
|
||||||
const isPageMode = this.isPageMode;
|
const isPageMode = this.isPageMode;
|
||||||
|
|
||||||
assertExists(syncedDoc);
|
if (!syncedDoc) {
|
||||||
|
console.error('Synced doc is not found');
|
||||||
|
return html`${nothing}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = new Store({ blocks: syncedDoc });
|
||||||
|
|
||||||
if (isPageMode) {
|
if (isPageMode) {
|
||||||
this.dataset.pageMode = '';
|
this.dataset.pageMode = '';
|
||||||
@@ -176,7 +186,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
|||||||
() => html`
|
() => html`
|
||||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: syncedDoc,
|
store,
|
||||||
extensions: this._buildPreviewSpec('page:preview'),
|
extensions: this._buildPreviewSpec('page:preview'),
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
@@ -187,7 +197,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
|||||||
() => html`
|
() => html`
|
||||||
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: syncedDoc,
|
store,
|
||||||
extensions: this._buildPreviewSpec('edgeless:preview'),
|
extensions: this._buildPreviewSpec('edgeless:preview'),
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ShadowlessElement,
|
ShadowlessElement,
|
||||||
} from '@blocksuite/block-std';
|
} from '@blocksuite/block-std';
|
||||||
import { deserializeXYWH, WithDisposable } from '@blocksuite/global/utils';
|
import { deserializeXYWH, WithDisposable } from '@blocksuite/global/utils';
|
||||||
import { type BlockModel, type Query } from '@blocksuite/store';
|
import { type BlockModel, type Query, Store } from '@blocksuite/store';
|
||||||
import { css, nothing } from 'lit';
|
import { css, nothing } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
@@ -118,9 +118,10 @@ export class SurfaceRefNotePortal extends WithDisposable(ShadowlessElement) {
|
|||||||
query: this.query,
|
query: this.query,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
});
|
});
|
||||||
|
const store = new Store({ blocks: doc });
|
||||||
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
||||||
return new BlockStdScope({
|
return new BlockStdScope({
|
||||||
doc,
|
store,
|
||||||
extensions: previewSpec.value.slice(),
|
extensions: previewSpec.value.slice(),
|
||||||
}).render();
|
}).render();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import {
|
|||||||
DisposableGroup,
|
DisposableGroup,
|
||||||
type SerializedXYWH,
|
type SerializedXYWH,
|
||||||
} from '@blocksuite/global/utils';
|
} from '@blocksuite/global/utils';
|
||||||
import type { Blocks } from '@blocksuite/store';
|
import { type Blocks, Store } from '@blocksuite/store';
|
||||||
import { css, html, nothing, type TemplateResult } from 'lit';
|
import { css, html, nothing, type TemplateResult } from 'lit';
|
||||||
import { query, state } from 'lit/decorators.js';
|
import { query, state } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
@@ -545,10 +545,15 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
|||||||
const _previewSpec = this._previewSpec.value;
|
const _previewSpec = this._previewSpec.value;
|
||||||
|
|
||||||
if (!this._viewportEditor) {
|
if (!this._viewportEditor) {
|
||||||
this._viewportEditor = new BlockStdScope({
|
if (this._previewDoc) {
|
||||||
doc: this._previewDoc!,
|
const store = new Store({ blocks: this._previewDoc });
|
||||||
extensions: _previewSpec,
|
this._viewportEditor = new BlockStdScope({
|
||||||
}).render();
|
store,
|
||||||
|
extensions: _previewSpec,
|
||||||
|
}).render();
|
||||||
|
} else {
|
||||||
|
console.error('Preview doc is not found');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<div class="ref-content">
|
return html`<div class="ref-content">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
type DndEventState,
|
type DndEventState,
|
||||||
} from '@blocksuite/block-std';
|
} from '@blocksuite/block-std';
|
||||||
import { Point } from '@blocksuite/global/utils';
|
import { Point } from '@blocksuite/global/utils';
|
||||||
import type { BlockViewType, Query } from '@blocksuite/store';
|
import { type BlockViewType, type Query, Store } from '@blocksuite/store';
|
||||||
|
|
||||||
import { DragPreview } from '../components/drag-preview.js';
|
import { DragPreview } from '../components/drag-preview.js';
|
||||||
import type { AffineDragHandleWidget } from '../drag-handle.js';
|
import type { AffineDragHandleWidget } from '../drag-handle.js';
|
||||||
@@ -82,8 +82,9 @@ export class PreviewHelper {
|
|||||||
const doc = this.widget.doc.doc.getBlocks({ query });
|
const doc = this.widget.doc.doc.getBlocks({ query });
|
||||||
|
|
||||||
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
||||||
|
const store = new Store({ blocks: doc });
|
||||||
const previewStd = new BlockStdScope({
|
const previewStd = new BlockStdScope({
|
||||||
doc,
|
store,
|
||||||
extensions: previewSpec.value,
|
extensions: previewSpec.value,
|
||||||
});
|
});
|
||||||
const previewTemplate = previewStd.render();
|
const previewTemplate = previewStd.render();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
DisposableGroup,
|
DisposableGroup,
|
||||||
WithDisposable,
|
WithDisposable,
|
||||||
} from '@blocksuite/global/utils';
|
} from '@blocksuite/global/utils';
|
||||||
import { type Blocks, type Query } from '@blocksuite/store';
|
import { type Blocks, type Query, Store } from '@blocksuite/store';
|
||||||
import { css, html, nothing, type PropertyValues } from 'lit';
|
import { css, html, nothing, type PropertyValues } from 'lit';
|
||||||
import { property, query, state } from 'lit/decorators.js';
|
import { property, query, state } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
@@ -155,6 +155,7 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
|||||||
private _renderSurfaceContent() {
|
private _renderSurfaceContent() {
|
||||||
if (!this._previewDoc || !this.frame) return nothing;
|
if (!this._previewDoc || !this.frame) return nothing;
|
||||||
const { width, height } = this.frameViewportWH;
|
const { width, height } = this.frameViewportWH;
|
||||||
|
const store = new Store({ blocks: this._previewDoc });
|
||||||
|
|
||||||
const _previewSpec = this._previewSpec.value;
|
const _previewSpec = this._previewSpec.value;
|
||||||
return html`<div
|
return html`<div
|
||||||
@@ -172,7 +173,7 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: this._previewDoc,
|
store,
|
||||||
extensions: _previewSpec,
|
extensions: _previewSpec,
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
||||||
import type { Blocks, ExtensionType } from '@blocksuite/store';
|
import { type Blocks, type ExtensionType, Store } from '@blocksuite/store';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { customElement, property } from 'lit/decorators.js';
|
import { customElement, property } from 'lit/decorators.js';
|
||||||
|
|
||||||
@@ -18,8 +18,9 @@ export class TestEditorContainer extends SignalWatcher(
|
|||||||
|
|
||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
const store = new Store({ blocks: this.doc });
|
||||||
this._std = new BlockStdScope({
|
this._std = new BlockStdScope({
|
||||||
doc: this.doc,
|
store,
|
||||||
extensions: this.specs,
|
extensions: this.specs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { ServiceProvider } from '@blocksuite/global/di';
|
import { Container, type ServiceProvider } from '@blocksuite/global/di';
|
||||||
import { Container } from '@blocksuite/global/di';
|
|
||||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||||
import {
|
import {
|
||||||
type Blocks,
|
|
||||||
type ExtensionType,
|
type ExtensionType,
|
||||||
Job,
|
Job,
|
||||||
type JobMiddleware,
|
type JobMiddleware,
|
||||||
|
type Store,
|
||||||
} from '@blocksuite/store';
|
} from '@blocksuite/store';
|
||||||
|
|
||||||
import { Clipboard } from '../clipboard/index.js';
|
import { Clipboard } from '../clipboard/index.js';
|
||||||
@@ -36,7 +35,7 @@ import { EditorHost } from '../view/element/index.js';
|
|||||||
import { ViewStore } from '../view/view-store.js';
|
import { ViewStore } from '../view/view-store.js';
|
||||||
|
|
||||||
export interface BlockStdOptions {
|
export interface BlockStdOptions {
|
||||||
doc: Blocks;
|
store: Store;
|
||||||
extensions: ExtensionType[];
|
extensions: ExtensionType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ export class BlockStdScope {
|
|||||||
|
|
||||||
readonly container: Container;
|
readonly container: Container;
|
||||||
|
|
||||||
readonly doc: Blocks;
|
readonly store: Store;
|
||||||
|
|
||||||
readonly provider: ServiceProvider;
|
readonly provider: ServiceProvider;
|
||||||
|
|
||||||
@@ -75,6 +74,10 @@ export class BlockStdScope {
|
|||||||
return this.provider.getAll(LifeCycleWatcherIdentifier);
|
return this.provider.getAll(LifeCycleWatcherIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get doc() {
|
||||||
|
return this.store.blocks;
|
||||||
|
}
|
||||||
|
|
||||||
get clipboard() {
|
get clipboard() {
|
||||||
return this.get(Clipboard);
|
return this.get(Clipboard);
|
||||||
}
|
}
|
||||||
@@ -122,7 +125,7 @@ export class BlockStdScope {
|
|||||||
'Host is not ready to use, the `render` method should be called first'
|
'Host is not ready to use, the `render` method should be called first'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
this.doc = options.doc;
|
this.store = options.store;
|
||||||
this.userExtensions = options.extensions;
|
this.userExtensions = options.extensions;
|
||||||
this.container = new Container();
|
this.container = new Container();
|
||||||
this.container.addImpl(StdIdentifier, () => this);
|
this.container.addImpl(StdIdentifier, () => this);
|
||||||
@@ -137,7 +140,7 @@ export class BlockStdScope {
|
|||||||
ext.setup(container);
|
ext.setup(container);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.provider = this.container.provider();
|
this.provider = this.container.provider(undefined, this.store.provider);
|
||||||
|
|
||||||
this._lifeCycleWatchers.forEach(watcher => {
|
this._lifeCycleWatchers.forEach(watcher => {
|
||||||
watcher.created.call(watcher);
|
watcher.created.call(watcher);
|
||||||
|
|||||||
17
blocksuite/framework/store/src/extension/extension.ts
Normal file
17
blocksuite/framework/store/src/extension/extension.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,17 +1,2 @@
|
|||||||
import type { Container } from '@blocksuite/global/di';
|
export * from './extension';
|
||||||
|
export * from './store-extension';
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|||||||
41
blocksuite/framework/store/src/extension/store-extension.ts
Normal file
41
blocksuite/framework/store/src/extension/store-extension.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ export * from './extension';
|
|||||||
export * from './model';
|
export * from './model';
|
||||||
export * from './reactive';
|
export * from './reactive';
|
||||||
export * from './schema';
|
export * from './schema';
|
||||||
|
export * from './store';
|
||||||
export * from './transformer';
|
export * from './transformer';
|
||||||
export { type IdGenerator, nanoid, uuidv4 } from './utils/id-generator';
|
export { type IdGenerator, nanoid, uuidv4 } from './utils/id-generator';
|
||||||
export * from './yjs';
|
export * from './yjs';
|
||||||
|
|||||||
5
blocksuite/framework/store/src/store/identifier.ts
Normal file
5
blocksuite/framework/store/src/store/identifier.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { createIdentifier } from '@blocksuite/global/di';
|
||||||
|
|
||||||
|
import type { Store } from './store';
|
||||||
|
|
||||||
|
export const StoreIdentifier = createIdentifier<Store>('Store');
|
||||||
2
blocksuite/framework/store/src/store/index.ts
Normal file
2
blocksuite/framework/store/src/store/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './identifier';
|
||||||
|
export * from './store';
|
||||||
41
blocksuite/framework/store/src/store/store.ts
Normal file
41
blocksuite/framework/store/src/store/store.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BlockStdScope, ShadowlessElement } from '@blocksuite/block-std';
|
import { BlockStdScope, ShadowlessElement } from '@blocksuite/block-std';
|
||||||
import { EdgelessEditorBlockSpecs, ThemeProvider } from '@blocksuite/blocks';
|
import { EdgelessEditorBlockSpecs, ThemeProvider } from '@blocksuite/blocks';
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
||||||
import type { Blocks } from '@blocksuite/store';
|
import { type Blocks, Store } from '@blocksuite/store';
|
||||||
import { css, html, nothing, type TemplateResult } from 'lit';
|
import { css, html, nothing, type TemplateResult } from 'lit';
|
||||||
import { property, state } from 'lit/decorators.js';
|
import { property, state } from 'lit/decorators.js';
|
||||||
import { guard } from 'lit/directives/guard.js';
|
import { guard } from 'lit/directives/guard.js';
|
||||||
@@ -48,8 +48,9 @@ export class EdgelessEditor extends SignalWatcher(
|
|||||||
this._disposables.add(
|
this._disposables.add(
|
||||||
this.doc.slots.rootAdded.on(() => this.requestUpdate())
|
this.doc.slots.rootAdded.on(() => this.requestUpdate())
|
||||||
);
|
);
|
||||||
|
const store = new Store({ blocks: this.doc });
|
||||||
this.std = new BlockStdScope({
|
this.std = new BlockStdScope({
|
||||||
doc: this.doc,
|
store,
|
||||||
extensions: this.specs,
|
extensions: this.specs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -77,8 +78,9 @@ export class EdgelessEditor extends SignalWatcher(
|
|||||||
) {
|
) {
|
||||||
super.willUpdate(changedProperties);
|
super.willUpdate(changedProperties);
|
||||||
if (changedProperties.has('doc')) {
|
if (changedProperties.has('doc')) {
|
||||||
|
const store = new Store({ blocks: this.doc });
|
||||||
this.std = new BlockStdScope({
|
this.std = new BlockStdScope({
|
||||||
doc: this.doc,
|
store,
|
||||||
extensions: this.specs,
|
extensions: this.specs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ import {
|
|||||||
ThemeProvider,
|
ThemeProvider,
|
||||||
} from '@blocksuite/blocks';
|
} from '@blocksuite/blocks';
|
||||||
import { SignalWatcher, Slot, WithDisposable } from '@blocksuite/global/utils';
|
import { SignalWatcher, Slot, WithDisposable } from '@blocksuite/global/utils';
|
||||||
import type { BlockModel, Blocks, ExtensionType } from '@blocksuite/store';
|
import {
|
||||||
|
type BlockModel,
|
||||||
|
type Blocks,
|
||||||
|
type ExtensionType,
|
||||||
|
Store,
|
||||||
|
} from '@blocksuite/store';
|
||||||
import { computed, signal } from '@preact/signals-core';
|
import { computed, signal } from '@preact/signals-core';
|
||||||
import { css, html } from 'lit';
|
import { css, html } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
@@ -100,9 +105,13 @@ export class AffineEditorContainer
|
|||||||
: this._edgelessSpecs.value
|
: this._edgelessSpecs.value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private readonly _store = computed(() => {
|
||||||
|
return new Store({ blocks: this.doc });
|
||||||
|
});
|
||||||
|
|
||||||
private readonly _std = computed(() => {
|
private readonly _std = computed(() => {
|
||||||
return new BlockStdScope({
|
return new BlockStdScope({
|
||||||
doc: this.doc,
|
store: this._store.value,
|
||||||
extensions: this._specs.value,
|
extensions: this._specs.value,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
} from '@blocksuite/block-std';
|
} from '@blocksuite/block-std';
|
||||||
import { PageEditorBlockSpecs, ThemeProvider } from '@blocksuite/blocks';
|
import { PageEditorBlockSpecs, ThemeProvider } from '@blocksuite/blocks';
|
||||||
import { noop, SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
import { noop, SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
|
||||||
import type { Blocks } from '@blocksuite/store';
|
import { type Blocks, Store } from '@blocksuite/store';
|
||||||
import { css, html, nothing } from 'lit';
|
import { css, html, nothing } from 'lit';
|
||||||
import { property, state } from 'lit/decorators.js';
|
import { property, state } from 'lit/decorators.js';
|
||||||
import { guard } from 'lit/directives/guard.js';
|
import { guard } from 'lit/directives/guard.js';
|
||||||
@@ -59,8 +59,9 @@ export class PageEditor extends SignalWatcher(
|
|||||||
this._disposables.add(
|
this._disposables.add(
|
||||||
this.doc.slots.rootAdded.on(() => this.requestUpdate())
|
this.doc.slots.rootAdded.on(() => this.requestUpdate())
|
||||||
);
|
);
|
||||||
|
const store = new Store({ blocks: this.doc });
|
||||||
this.std = new BlockStdScope({
|
this.std = new BlockStdScope({
|
||||||
doc: this.doc,
|
store,
|
||||||
extensions: this.specs,
|
extensions: this.specs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -93,8 +94,9 @@ export class PageEditor extends SignalWatcher(
|
|||||||
) {
|
) {
|
||||||
super.willUpdate(changedProperties);
|
super.willUpdate(changedProperties);
|
||||||
if (changedProperties.has('doc')) {
|
if (changedProperties.has('doc')) {
|
||||||
|
const store = new Store({ blocks: this.doc });
|
||||||
this.std = new BlockStdScope({
|
this.std = new BlockStdScope({
|
||||||
doc: this.doc,
|
store,
|
||||||
extensions: this.specs,
|
extensions: this.specs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
type JobMiddleware,
|
type JobMiddleware,
|
||||||
type Query,
|
type Query,
|
||||||
type Schema,
|
type Schema,
|
||||||
|
Store,
|
||||||
} from '@blocksuite/affine/store';
|
} from '@blocksuite/affine/store';
|
||||||
import { css, html, nothing, type PropertyValues } from 'lit';
|
import { css, html, nothing, type PropertyValues } from 'lit';
|
||||||
import { property, query } from 'lit/decorators.js';
|
import { property, query } from 'lit/decorators.js';
|
||||||
@@ -286,7 +287,7 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
|||||||
this._doc,
|
this._doc,
|
||||||
html`<div class="ai-answer-text-editor affine-page-viewport">
|
html`<div class="ai-answer-text-editor affine-page-viewport">
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: this._doc,
|
store: new Store({ blocks: this._doc }),
|
||||||
extensions: this.options.extensions ?? CustomPageEditorBlockSpecs,
|
extensions: this.options.extensions ?? CustomPageEditorBlockSpecs,
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import { AffineSchemas } from '@blocksuite/affine/blocks/schemas';
|
import { AffineSchemas } from '@blocksuite/affine/blocks/schemas';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/utils';
|
import { WithDisposable } from '@blocksuite/affine/global/utils';
|
||||||
import type { Blocks } from '@blocksuite/affine/store';
|
import type { Blocks } from '@blocksuite/affine/store';
|
||||||
import { Schema } from '@blocksuite/affine/store';
|
import { Schema, Store } from '@blocksuite/affine/store';
|
||||||
import { css, html, LitElement, nothing } from 'lit';
|
import { css, html, LitElement, nothing } from 'lit';
|
||||||
import { property, query } from 'lit/decorators.js';
|
import { property, query } from 'lit/decorators.js';
|
||||||
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
import { createRef, type Ref, ref } from 'lit/directives/ref.js';
|
||||||
@@ -208,7 +208,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
|||||||
${ref(this._editorContainer)}
|
${ref(this._editorContainer)}
|
||||||
>
|
>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: this._doc,
|
store: new Store({ blocks: this._doc }),
|
||||||
extensions:
|
extensions:
|
||||||
SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
||||||
}).render()}
|
}).render()}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import type { ServiceProvider } from '@blocksuite/affine/global/di';
|
import type { ServiceProvider } from '@blocksuite/affine/global/di';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/utils';
|
import { WithDisposable } from '@blocksuite/affine/global/utils';
|
||||||
import { type Blocks, Job, Schema } from '@blocksuite/affine/store';
|
import { type Blocks, Job, Schema, Store } from '@blocksuite/affine/store';
|
||||||
import { css, html, LitElement, nothing } from 'lit';
|
import { css, html, LitElement, nothing } from 'lit';
|
||||||
import { property, query } from 'lit/decorators.js';
|
import { property, query } from 'lit/decorators.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
@@ -175,7 +175,7 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
${new BlockStdScope({
|
${new BlockStdScope({
|
||||||
doc: this.doc,
|
store: new Store({ blocks: this.doc }),
|
||||||
extensions: MiniMindmapSpecs,
|
extensions: MiniMindmapSpecs,
|
||||||
}).render()}
|
}).render()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
ThemeExtensionIdentifier,
|
ThemeExtensionIdentifier,
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import { Bound } from '@blocksuite/affine/global/utils';
|
import { Bound } from '@blocksuite/affine/global/utils';
|
||||||
import type { Block, Blocks } from '@blocksuite/affine/store';
|
import { type Block, type Blocks, Store } from '@blocksuite/affine/store';
|
||||||
import { createSignalFromObservable } from '@blocksuite/affine-shared/utils';
|
import { createSignalFromObservable } from '@blocksuite/affine-shared/utils';
|
||||||
import type { Container } from '@blocksuite/global/di';
|
import type { Container } from '@blocksuite/global/di';
|
||||||
import type { Signal } from '@preact/signals-core';
|
import type { Signal } from '@preact/signals-core';
|
||||||
@@ -90,7 +90,7 @@ export const EdgelessSnapshot = (props: Props) => {
|
|||||||
if (!doc) return;
|
if (!doc) return;
|
||||||
|
|
||||||
const editorHost = new BlockStdScope({
|
const editorHost = new BlockStdScope({
|
||||||
doc,
|
store: new Store({ blocks: doc }),
|
||||||
extensions: [
|
extensions: [
|
||||||
...SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
...SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
||||||
getThemeExtension(framework),
|
getThemeExtension(framework),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { createPageModeSpecs } from '@affine/core/components/blocksuite/block-su
|
|||||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||||
import { BlockStdScope } from '@blocksuite/affine/block-std';
|
import { BlockStdScope } from '@blocksuite/affine/block-std';
|
||||||
import { DndApiExtensionIdentifier } from '@blocksuite/affine/blocks';
|
import { DndApiExtensionIdentifier } from '@blocksuite/affine/blocks';
|
||||||
import { type SliceSnapshot } from '@blocksuite/affine/store';
|
import { type SliceSnapshot, Store } from '@blocksuite/affine/store';
|
||||||
import { Service } from '@toeverything/infra';
|
import { Service } from '@toeverything/infra';
|
||||||
|
|
||||||
import type { DocsService } from '../../doc';
|
import type { DocsService } from '../../doc';
|
||||||
@@ -69,7 +69,7 @@ export class DndService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std = new BlockStdScope({
|
const std = new BlockStdScope({
|
||||||
doc,
|
store: new Store({ blocks: doc }),
|
||||||
extensions: createPageModeSpecs(this.framework),
|
extensions: createPageModeSpecs(this.framework),
|
||||||
});
|
});
|
||||||
const dndAPI = std.get(DndApiExtensionIdentifier);
|
const dndAPI = std.get(DndApiExtensionIdentifier);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { DebugLogger } from '@affine/debug';
|
import { DebugLogger } from '@affine/debug';
|
||||||
import { BlockStdScope } from '@blocksuite/affine/block-std';
|
import { BlockStdScope } from '@blocksuite/affine/block-std';
|
||||||
import { PageEditorBlockSpecs } from '@blocksuite/affine/blocks';
|
import { PageEditorBlockSpecs } from '@blocksuite/affine/blocks';
|
||||||
import type { Blocks } from '@blocksuite/affine/store';
|
import { type Blocks, Store } from '@blocksuite/affine/store';
|
||||||
import { LiveData } from '@toeverything/infra';
|
import { LiveData } from '@toeverything/infra';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
@@ -45,7 +45,7 @@ export function signalToLiveData<T>(
|
|||||||
export function createBlockStdScope(doc: Blocks) {
|
export function createBlockStdScope(doc: Blocks) {
|
||||||
logger.debug('createBlockStdScope', doc.id);
|
logger.debug('createBlockStdScope', doc.id);
|
||||||
const std = new BlockStdScope({
|
const std = new BlockStdScope({
|
||||||
doc,
|
store: new Store({ blocks: doc }),
|
||||||
extensions: PageEditorBlockSpecs,
|
extensions: PageEditorBlockSpecs,
|
||||||
});
|
});
|
||||||
return std;
|
return std;
|
||||||
|
|||||||
Reference in New Issue
Block a user